297 lines
9.7 KiB
TypeScript
297 lines
9.7 KiB
TypeScript
import { defineStore } from 'pinia';
|
|
import apiError from '@/module/apiError';
|
|
import piniaLoginStore from '@/stores/login.ts';
|
|
import { JUST_CREATE_ACCOUNT_HOT_DURATION_MINS } from '@/constants/constants';
|
|
|
|
interface User {
|
|
username: string;
|
|
detail: Record<string, any>;
|
|
name?: string;
|
|
is_admin?: boolean;
|
|
is_sso?: boolean;
|
|
isDeleteHovered?: boolean;
|
|
isRowHovered?: boolean;
|
|
isEditHovered?: boolean;
|
|
isDetailHovered?: boolean;
|
|
}
|
|
|
|
interface EditDetail {
|
|
newUsername?: string;
|
|
username?: string;
|
|
password: string;
|
|
name: string;
|
|
is_active: boolean;
|
|
}
|
|
|
|
const loginStore = piniaLoginStore();
|
|
|
|
export default defineStore('acctMgmtStore', {
|
|
state: () => ({
|
|
allUserAccoutList: [] as User[],
|
|
isAcctMenuOpen: false,
|
|
currentViewingUser: {
|
|
username: '',
|
|
detail: {},
|
|
} as User,
|
|
response: {
|
|
deleteAccount: null,
|
|
},
|
|
isOneAccountJustCreate: false, //如果有一個帳號剛剛建立,則會在列表上的第一列顯示這個帳號,並且右置一個徽章
|
|
justCreateUsername: '', // unique username
|
|
shouldUpdateList: false, // 控制是否該刷新列表
|
|
}),
|
|
getters: {},
|
|
actions: {
|
|
/**
|
|
* Set related boolean to true
|
|
*/
|
|
openAcctMenu() {
|
|
this.isAcctMenuOpen = true;
|
|
},
|
|
/**
|
|
* Set related boolean to false
|
|
*/
|
|
closeAcctMenu() {
|
|
this.isAcctMenuOpen = false;
|
|
},
|
|
toggleIsAcctMenuOpen() {
|
|
this.isAcctMenuOpen = !this.isAcctMenuOpen;
|
|
},
|
|
/**
|
|
* For convenience, set current viewing data according to unique user ID.
|
|
* @param {string} username
|
|
*/
|
|
setCurrentViewingUser(username: string) {
|
|
const userFind: User | undefined = this.allUserAccoutList.find(user => user.username === username);
|
|
console.log('userFind', userFind);
|
|
this.currentViewingUser = userFind || { username: '', detail: {} };
|
|
},
|
|
/**
|
|
* We have this method because we want to handle create new modal case.
|
|
*/
|
|
clearCurrentViewingUser() {
|
|
this.currentViewingUser = {
|
|
username: '',
|
|
detail: {},
|
|
name: '',
|
|
is_admin: false,
|
|
is_sso: false,
|
|
isDeleteHovered: false,
|
|
isRowHovered: false,
|
|
isEditHovered: false,
|
|
isDetailHovered: false,
|
|
};
|
|
},
|
|
/**
|
|
* Get all user accounts
|
|
*/
|
|
async getAllUserAccounts() {
|
|
const apiGetUserList = `/api/users`;
|
|
try {
|
|
const response = await this.$axios.get(apiGetUserList);
|
|
const customizedResponseData = await this.customizeAllUserList(response.data);
|
|
this.allUserAccoutList = await this.moveCurrentLoginUserToFirstRow(customizedResponseData);
|
|
} catch (error) {
|
|
apiError(error, 'Failed to get all users.');
|
|
}
|
|
},
|
|
/**
|
|
* Add some customization. For example, add isHovered field
|
|
*/
|
|
async customizeAllUserList(rawResponseData: User[]): Promise<User[]> {
|
|
return rawResponseData.map(user => ({
|
|
...user, // 保留後端傳來的欄位
|
|
isDeleteHovered: false, // 針對前端顯示而額外增加的欄位
|
|
isRowHovered: false,
|
|
isEditHovered: false,
|
|
}));
|
|
},
|
|
/**
|
|
* Current logged in user should be placed at the first row on list
|
|
*/
|
|
async moveCurrentLoginUserToFirstRow(fetchedUserList: User[]): Promise<User[]> {
|
|
await loginStore.getUserData();
|
|
const loginUserData:User = loginStore.userData;
|
|
const foundLoginUserIndex = fetchedUserList.findIndex(user => user.username === loginUserData.username);
|
|
fetchedUserList.unshift(fetchedUserList.splice(foundLoginUserIndex, 1)[0]);
|
|
return fetchedUserList;
|
|
},
|
|
/**
|
|
* Create new user in database.
|
|
* @param {object} userToCreate
|
|
* userToCreate {
|
|
* "username": "string",
|
|
* "password": "string",
|
|
* "name": "string",
|
|
* "is_admin": boolean,
|
|
* "is_active": boolean,
|
|
* }
|
|
*/
|
|
async createNewAccount(userToCreate: User) {
|
|
const apiCreateAccount = `/api/users`;
|
|
|
|
try {
|
|
const response = await this.$axios.post(apiCreateAccount, userToCreate);
|
|
if (response.status === 200) {
|
|
this.isOneAccountJustCreate = true;
|
|
this.justCreateUsername = userToCreate.username;
|
|
setTimeout(this.resetJustCreateFlag, JUST_CREATE_ACCOUNT_HOT_DURATION_MINS * 1000 * 60);
|
|
}
|
|
} catch (error) {
|
|
apiError(error, 'Failed to add a new account.');
|
|
}
|
|
},
|
|
/**
|
|
* Delete an account from database.
|
|
* @param {string} userToDelete this value is unique in database.
|
|
* @returns the result of whether the deletion is success or not.
|
|
*/
|
|
async deleteAccount(userToDelete: string): Promise<boolean> {
|
|
const apiDelete = `/api/users/${userToDelete}`;
|
|
|
|
try {
|
|
const response = await this.$axios.delete(apiDelete);
|
|
return response.status === 200;
|
|
} catch (error) {
|
|
apiError(error, 'Failed to delete the account.');
|
|
return false;
|
|
}
|
|
},
|
|
/**
|
|
* Edit an account.
|
|
* @param {string} userToEdit this value is unique in database.
|
|
* @param {object} editDetail
|
|
*/
|
|
async editAccount(userToEdit: string, editDetail: EditDetail): Promise<boolean> {
|
|
const apiEdit = `/api/users/${userToEdit}`;
|
|
|
|
try {
|
|
const response = await this.$axios.put(apiEdit, {
|
|
username: editDetail.newUsername ? editDetail.newUsername : editDetail.username,
|
|
password: editDetail.password,
|
|
name: editDetail.name,
|
|
is_active: editDetail.is_active,
|
|
});
|
|
return response.status === 200;
|
|
} catch (error) {
|
|
apiError(error, 'Failed to edit the account.');
|
|
return false;
|
|
}
|
|
},
|
|
/** Add a role to the user in database.
|
|
* @param {string} usernameToEdit
|
|
* @param {string} roleCode
|
|
*/
|
|
async addRoleToUser(usernameToEdit: string, roleCode: string): Promise<boolean> {
|
|
const apiAddRole = `/api/users/${usernameToEdit}/roles/${roleCode}`;
|
|
|
|
try {
|
|
const response = await this.$axios.put(apiAddRole);
|
|
return response.status === 200;
|
|
} catch (error) {
|
|
apiError(error, 'Failed to add role to the account.');
|
|
return false;
|
|
}
|
|
},
|
|
/** Delete a role from the user in database.
|
|
* @param {string} usernameToEdit
|
|
* @param {string} roleCode
|
|
*/
|
|
async deleteRoleToUser(usernameToEdit: string, roleCode: string): Promise<boolean> {
|
|
const apiDeleteRole = `/api/users/${usernameToEdit}/roles/${roleCode}`;
|
|
|
|
try {
|
|
const response = await this.$axios.delete(apiDeleteRole);
|
|
return response.status === 200;
|
|
} catch (error) {
|
|
apiError(error, 'Failed to delete a role frome the account.');
|
|
return false;
|
|
}
|
|
},
|
|
/**
|
|
* Get user detail by unique username.
|
|
* @param {string} uniqueUsername
|
|
*/
|
|
async getUserDetail(uniqueUsername: string): Promise<boolean> {
|
|
const apiUserDetail = `/api/users/${uniqueUsername}`;
|
|
|
|
try {
|
|
const response = await this.$axios.get(apiUserDetail);
|
|
this.currentViewingUser = {
|
|
...this.currentViewingUser,
|
|
detail: response.data,
|
|
};
|
|
return response.status === 200;
|
|
} catch (error) {
|
|
//不需要跳出錯誤,因為如果是錯誤反而是好事,表示帳號是獨一的
|
|
return false;
|
|
}
|
|
},
|
|
/**
|
|
* According to mouseover or mouseleave status, change the bool value.
|
|
* @param {string} username
|
|
* @param {boolean} isDeleteHovered
|
|
*/
|
|
changeIsDeleteHoveredByUser(username: string, isDeleteHovered: boolean) {
|
|
const userToChange = this.allUserAccoutList.find(user => user.username === username);
|
|
if (userToChange) {
|
|
userToChange.isDeleteHovered = isDeleteHovered;
|
|
}
|
|
},
|
|
/**
|
|
* According to mouseover or mouseleave status, change the bool value.
|
|
* @param {string} username
|
|
* @param {boolean} isRowHovered
|
|
*/
|
|
changeIsRowHoveredByUser(username: string, isRowHovered: boolean) {
|
|
const userToChange = this.allUserAccoutList.find(user => user.username === username);
|
|
if (userToChange) {
|
|
userToChange.isRowHovered = isRowHovered;
|
|
}
|
|
},
|
|
/**
|
|
* According to mouseover or mouseleave status, change the bool value.
|
|
* @param {string} username
|
|
* @param {boolean} isEditHovered
|
|
*/
|
|
changeIsEditHoveredByUser(username: string, isEditHovered: boolean) {
|
|
const userToChange = this.allUserAccoutList.find(user => user.username === username);
|
|
if (userToChange) {
|
|
userToChange.isEditHovered = isEditHovered;
|
|
}
|
|
},
|
|
/**
|
|
* According to mouseover or mouseleave status, change the bool value.
|
|
* @param {string} username
|
|
* @param {boolean} isEditHovered
|
|
*/
|
|
changeIsDetailHoveredByUser(username: string, isDetailHovered: boolean) {
|
|
const userToChange = this.allUserAccoutList.find(user => user.username === username);
|
|
if (userToChange) {
|
|
userToChange.isDetailHovered = isDetailHovered;
|
|
}
|
|
},
|
|
/**
|
|
* Reset isOneAccountJustCreate to false, causing the badge to disappear.
|
|
*/
|
|
resetJustCreateFlag() {
|
|
this.isOneAccountJustCreate = false;
|
|
},
|
|
/** Set the value of shouldUpdateList variable.
|
|
* @param {boolean} shouldUpdateBoolean
|
|
*/
|
|
setShouldUpdateList(shouldUpdateBoolean: boolean) {
|
|
this.shouldUpdateList = shouldUpdateBoolean;
|
|
},
|
|
/** Only update one single account in the pinia state.
|
|
* @param {object} userDataToReplace
|
|
*/
|
|
updateSingleAccountPiniaState(userDataToReplace: User) {
|
|
const userIndex = this.allUserAccoutList.findIndex(user => user.username === userDataToReplace.username);
|
|
if (userIndex !== -1) {
|
|
this.allUserAccoutList[userIndex] = { ...this.allUserAccoutList[userIndex], ...userDataToReplace };
|
|
}
|
|
}
|
|
},
|
|
});
|