Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bi-web",
"version": "v1.2.0+877",
"version": "v1.2.0+883",
"private": true,
"scripts": {
"build": "node $npm_package_config_task_path/build.js --dev-audit-level=critical --prod-audit-level=none",
Expand Down Expand Up @@ -96,5 +96,5 @@
"vue-cli-plugin-axios": "0.0.4",
"vue-template-compiler": "^2.7.14"
},
"versionInfo": "https://github.com/Breeding-Insight/bi-web/commit/a0057d50e0ca4f0091ae14cef641f56b24110ab3"
"versionInfo": "https://github.com/Breeding-Insight/bi-web/commit/c6827820f268a811a67ad2e3576b3412e4e32c70"
}
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
3 changes: 1 addition & 2 deletions src/views/import/ImportGermplasm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
<p>New Germplasm count: {{ statistics.Germplasm.newObjectCount }}</p>
<p>New Pedigree Connections: {{ statistics["Pedigree Connections"].newObjectCount }}</p>
<template v-if="duplicatesPresent(rows)">
<p>Duplicate names detected and are highlighted in yellow and show a <alert-triangle-icon size="1.2x" class="icon-align"/> icon.
Upon import duplicates will become independent database entries.</p>
<p>Duplicate names detected and are highlighted in yellow and show a <alert-triangle-icon size="1.2x" class="icon-align"/> icon.</p>
</template>

</div>
Expand Down
1 change: 1 addition & 0 deletions task/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const port = process.env.PORT || JSON.parse(fs.readFileSync('package.json', 'utf
(async () => {
let spinner = ora({prefixText: ' ', color: 'yellow'});
try {

//TODO: Pinning version did not fix npm sort issue. Tempoarily commenting out to enable TAF runs, will be fixed in BI-2657
/*
spinner = spinner.start('sort package.json');
Expand Down