Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/breeding-insight/dao/UserDAO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {BiResponse} from "@/breeding-insight/model/BiResponse";
import {Role} from "@/breeding-insight/model/Role";
import {PaginationQuery} from "@/breeding-insight/model/PaginationQuery";
import {UserSort} from "@/breeding-insight/model/Sort";
import {SearchRequest} from "@/breeding-insight/model/SearchRequest";

export class UserDAO {

Expand Down Expand Up @@ -101,6 +102,40 @@ export class UserDAO {

}

static getById(id: string): Promise<BiResponse> {
return new Promise<BiResponse>((resolve, reject) => {
api.call({ url: `${process.env.VUE_APP_BI_API_V1_PATH}/users/${id}`, method: 'get' })
.then((response: any) => {
const biResponse = new BiResponse(response.data);
resolve(biResponse);
}).catch((error) => reject(error));
});
}

static search(searchRequest: SearchRequest, {page, pageSize}: PaginationQuery, {field, order}: UserSort): Promise<BiResponse> {

return new Promise<BiResponse>(((resolve, reject) => {
const config = {
url: `${process.env.VUE_APP_BI_API_V1_PATH}/users/search`,
method: 'post',
data: searchRequest,
params: {
sortField: field,
sortOrder: order,
page,
pageSize
}
}
api.call(config)
.then((response: any) => {
const biResponse = new BiResponse(response.data);
resolve(biResponse);
}).catch((error) => {
reject(error);
})
}));
}

static updateSystemRoles(id: string, systemRoles: Array<Role>) {

return new Promise<BiResponse>((resolve, reject) => {
Expand Down
26 changes: 26 additions & 0 deletions src/breeding-insight/model/FilterRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export class FilterRequest {
field: string;
value: string;

constructor(field: string, value: string) {
this.field = field;
this.value = value;
}
}
26 changes: 26 additions & 0 deletions src/breeding-insight/model/SearchRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {FilterRequest} from "@/breeding-insight/model/FilterRequest";

export class SearchRequest {
filters: FilterRequest[] = [];

constructor(filters: FilterRequest[]) {
this.filters = filters;
}
}
44 changes: 43 additions & 1 deletion src/breeding-insight/service/UserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ import {Program} from "@/breeding-insight/model/Program";
import {ProgramUser} from "@/breeding-insight/model/ProgramUser";
import {PaginationQuery} from "@/breeding-insight/model/PaginationQuery";
import {ProgramSort, SortOrder, UserSort, UserSortField} from "@/breeding-insight/model/Sort";
import {SearchRequest} from "@/breeding-insight/model/SearchRequest";

export class UserService {

static duplicateEmailMessage : string = 'Email is already in use.';
static errorCreateUser: string = 'Unable to create user';
static errorDeleteUser: string = 'Unable to archive user';
static errorGetUsers: string = 'Error while trying to load roles';
static errorGetUsers: string = 'Error while trying to load users';
static errorSearchUsers: string = 'Error while searching users';
static errorGetUser: string = 'User not found';
static errorDeleteUserNotFound: string = 'Unable to find user to deactivate';
static errorDeleteUserNotAllowed: string = 'You are not allowed to deactivate this user.';
static errorPermissionsEditUser: string = "You don't have permissions to edit the roles of this user.";
Expand Down Expand Up @@ -153,6 +156,45 @@ export class UserService {
}));
}

static getById(id: string): Promise<User> {
return new Promise<User>((resolve, reject) => {
UserDAO.getById(id).then((biResponse: BiResponse) => {
const result: any = biResponse.result;
const role: Role | undefined = this.parseSystemRoles(result.systemRoles);
const programRoles: ProgramUser[] | undefined = this.parseProgramRoles(result.programRoles);
const user = new User(result.id, result.name, result.orcid, result.email, role, programRoles);
resolve(user);
}).catch((error) => {
error['errorMessage'] = this.errorGetUser;
reject(error);
});
});
}

static search(searchRequest: SearchRequest,
paginationQuery: PaginationQuery = new PaginationQuery(1, 50, true),
sort: UserSort = new UserSort(UserSortField.Name, SortOrder.Ascending)): Promise<[User[], Metadata]> {
return new Promise<[User[], Metadata]>(((resolve, reject) => {

UserDAO.search(searchRequest, paginationQuery, sort).then((biResponse) => {

// Parse our users into the vue users param
let users = biResponse.result.data.map((user: any) => {
const role: Role | undefined = this.parseSystemRoles(user.systemRoles);
const programRoles: ProgramUser[] | undefined = this.parseProgramRoles(user.programRoles);
return new User(user.id, user.name, user.orcid, user.email, role, programRoles);
});

resolve([users, biResponse.metadata]);

}).catch((error) => {
error['errorMessage'] = this.errorSearchUsers;
reject(error)
});

}));
}

static updateSystemRoles(user: User): Promise<User> {

return new Promise<User>((resolve, reject) => {
Expand Down
72 changes: 33 additions & 39 deletions src/components/program/ProgramUsersTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@
import {
UPDATE_PROGRAM_USER_SORT
} from "@/store/sorting/mutation-types";
import {SearchRequest} from "@/breeding-insight/model/SearchRequest";
import {FilterRequest} from "@/breeding-insight/model/FilterRequest";

@Component({
components: { ExpandableTable, NewDataForm, BasicInputField, BasicSelectField, TableColumn,
Expand Down Expand Up @@ -218,7 +220,6 @@ export default class ProgramUsersTable extends Vue {
private activeProgram?: Program;
private activeUser?: User;
public users: ProgramUser[] = [];
public systemUsers: User[] = [];

private deactivateActive: boolean = false;
private newUserActive: boolean = false;
Expand Down Expand Up @@ -252,7 +253,6 @@ export default class ProgramUsersTable extends Vue {

mounted() {
this.getRoles();
this.getSystemUsers();
this.paginationChanged();
}

Expand Down Expand Up @@ -333,41 +333,40 @@ export default class ProgramUsersTable extends Vue {

}

saveUser() {
async saveUser() {

this.newUser.program = this.activeProgram;

try {
this.newUser = this.checkExistingUserByEmail(this.newUser, this.systemUsers);
this.newUser = await this.checkExistingUserByEmail(this.newUser);
} catch (err) {
this.$emit('show-error-notification', err);
this.newUserFormState.bus.$emit(DataFormEventBusHandler.SAVE_COMPLETE_EVENT);
return;
}

// if we found a system user by email in checkExistingUserByEmail then system user exists
const systemUserExisted = this.newUser.id !== undefined;

ProgramUserService.create(this.newUser).then((user: ProgramUser) => {
this.paginationController.updatePage(1);
this.paginationController.updateOnAdd();
this.getUsers();
this.getSystemUsers();

// See if the user already existed
//TODO: Reconsider when user search feature is added
if (this.getSystemUserById(user, this.systemUsers)) {
if (systemUserExisted) {
this.$emit('show-success-notification', 'Success! Existing user ' + user.name + ' added to program.');
} else {
this.$emit('show-success-notification', 'Success! ' + this.newUser.name + ' added.');
}

if(this.newUser.email === this.activeUser!.email) this.updateActiveUser();

this.getSystemUsers();
this.newUser = new ProgramUser();
this.newUserActive = false;
}).catch((error) => {
this.$emit('show-error-notification', error.errorMessage);
this.getUsers();
this.getSystemUsers();
}).finally(() => this.newUserFormState.bus.$emit(DataFormEventBusHandler.SAVE_COMPLETE_EVENT))

}
Expand All @@ -379,47 +378,42 @@ export default class ProgramUsersTable extends Vue {
Vue.prototype.$ability.update(rules);
}

//TODO: Reconsider when user search feature is added
getSystemUsers() {
//TODO: Do we still want this since orcid entry is removed?
async checkExistingUserByEmail(user: ProgramUser): Promise<ProgramUser> {
user.id = undefined;
// api call to check if user exists for email
// this was done on front-end before because we didn't have search endpoint at the time
const filter = new FilterRequest('email', user.email);
const request = new SearchRequest(filter);

UserService.getAll().then(([users, metadata]) => {
this.systemUsers = users;
}).catch((error) => {
try {
const [users, metadata] = await UserService.search(request);
// email exists
if (users.length === 1) {
user.id = users[0].id;
}
} catch (error) {
// Display error that users cannot be loaded
this.$emit('show-error-notification', 'Error while trying to load system users');
throw error;
});

}

//TODO: Reconsider when user search feature is added
//TODO: Do we still want this since orcid entry is removed?
checkExistingUserByEmail(user: ProgramUser, systemUsers: User[]): ProgramUser {
user.id = undefined;
let usersFound = 0;
for (const systemUser of systemUsers){
if (user.email === systemUser.email){
usersFound += 1;
if (systemUser.id){
user.id = systemUser.id;
}
}
}

if (usersFound > 1){
throw "Email matches two different users.";
}

return user;
}

//TODO: Reconsider when user search feature is added
getSystemUserById(user: ProgramUser, systemUsers: User[]): User | undefined {
for (const systemUser of systemUsers){
if (user.id === systemUser.id){
return systemUser;
getSystemUserById(user: ProgramUser): User | undefined {

UserService.getById(user.id).then(([users, metadata]) => {
if (users.length === 1) {
return users[0];
}
}
}).catch((error) => {
// Display error that users cannot be loaded
this.$emit('show-error-notification', 'Error while trying to load system user');
throw error;
});

return undefined;
}

Expand Down