feat(api): user store now handels deleted users.

`.users` now is a getter that filters out deleted users.
For all users, including deleted, use `_users` property (should not be needed as `getUser` will return the needed information as well).
This commit is contained in:
Ferdinand Thiessen 2021-12-05 20:57:15 +01:00
parent 9eb5412c14
commit f27212f60e
1 changed files with 97 additions and 32 deletions

View File

@ -11,81 +11,134 @@ export const useUserStore = defineStore({
state: () => ({
roles: [] as FG.Role[],
users: [] as FG.User[],
permissions: [] as FG.Permission[],
_dirty_users: true,
_dirty_roles: true,
// list of all users, include deleted ones, use `users` getter for list of active ones
_users: [] as FG.User[],
// Internal flags for deciding if lists need to force-loaded
}),
getters: {},
getters: {
users(state) {
return state._users.filter((u) => !u.deleted);
},
},
actions: {
/** Simply filter all users by ID */
findUser(userid: string) {
return this.users.find((user) => user.userid === userid);
return this._users.find((user) => user.userid === userid);
},
/** Retrieve user by ID
* @param userid ID of user to retrieve
* @param force If set to true the user is loaded from backend even when a local copy is available
* @returns Retrieved user (Promise) or raise an error
* @throws Probably an AxiosError if loading failed
*/
async getUser(userid: string, force = false) {
const idx = this.users.findIndex((user) => user.userid === userid);
if (force || this._dirty_users || idx === -1) {
const idx = this._users.findIndex((user) => user.userid === userid);
try {
const { data } = await api.get<FG.User>(`/users/${userid}`);
fixUser(data);
if (idx === -1) this.users.push(data);
else this.users[idx] = data;
if (idx === -1) this._users.push(data);
else this._users[idx] = data;
return data;
} catch (error) {
// Ignore 404, throw all other
if (!isAxiosError(error, 404)) throw error;
}
} else {
return this.users[idx];
return this._users[idx];
}
},
/** Retrieve list of all users
* @param force If set to true a fresh users list is loaded from backend even when a local copy is available
* @returns Array of retrieved users (Promise)
* @throws Probably an AxiosError if loading failed
*/
async getUsers(force = false) {
if (force || this._dirty_users) {
const { data } = await api.get<FG.User[]>('/users');
data.forEach(fixUser);
this.users = data;
this._dirty_users = false;
this._users = data;
}
return this.users;
return this._users;
},
/** Save modifications of user on backend
* @param user Modified user to save
* @throws Probably an AxiosError if request failed (404 = Invalid userid, 400 = Invalid data)
*/
async updateUser(user: FG.User) {
await api.put(`/users/${user.userid}`, user);
// Modifcation accepted by backend
// Save modifications back to our users list
const idx = this._users.findIndex((u) => u.userid === user.userid);
if (idx > -1) this._users[idx] = user;
// If user was current user, save modifications back to the main store
const mainStore = useMainStore();
if (user.userid === mainStore.user?.userid) mainStore.user = user;
this._dirty_users = true;
},
/** Register a new user
* @param user User to register (id not set)
* @returns The registered user (id set)
* @throws Probably an AxiosError if request failed
*/
async createUser(user: FG.User) {
const { data } = await api.post<FG.User>('/users', user);
this.users.push(data);
this._users.push(<FG.User>fixUser(data));
return data;
},
/** Delete an user
* Throws if failed and resolves void if succeed
*
* @param user User or ID of user to delete
* @throws Probably an AxiosError if request failed
*/
async deleteUser(user: FG.User | string) {
if (typeof user === 'object') user = user.userid;
await api.delete(`/users/${user}`);
this.users = this.users.filter(u => u.userid != user);
this._users = this._users.filter((u) => u.userid != user);
},
async uploadAvatar(user: FG.User, file: string | File) {
/** Upload an avatar for an user
* Throws if failed and resolves void if succeed
*
* @param user User or ID of user
* @param file Avatar file to upload
* @throws Probably an AxiosError if request failed
*/
async uploadAvatar(user: FG.User | string, file: string | File) {
if (typeof user === 'object') user = user.userid;
const formData = new FormData();
formData.append('file', file);
await api.post(`/users/${user.userid}/avatar`, formData, {
await api.post(`/users/${user}/avatar`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
},
async deleteAvatar(user: FG.User) {
await api.delete(`/users/${user.userid}/avatar`);
/** Delete avatar of an user
* @param user User or ID of user
* @throws Probably an AxiosError if request failed
*/
async deleteAvatar(user: FG.User | string) {
if (typeof user === 'object') user = user.userid;
await api.delete(`/users/${user}/avatar`);
},
/** Retrieve list of all permissions
* @param force If set to true a fresh list is loaded from backend even when a local copy is available
* @returns Array of retrieved permissions (Promise)
* @throws Probably an AxiosError if request failed
*/
async getPermissions(force = false) {
if (force || this.permissions.length === 0) {
const { data } = await api.get<FG.Permission[]>('/roles/permissions');
@ -94,6 +147,11 @@ export const useUserStore = defineStore({
return this.permissions;
},
/** Retrieve list of all roles
* @param force If set to true a fresh list is loaded from backend even when a local copy is available
* @returns Array of retrieved roles (Promise)
* @throws Probably an AxiosError if request failed
*/
async getRoles(force = false) {
if (force || this._dirty_roles) {
const { data } = await api.get<FG.Role[]>('/roles');
@ -103,30 +161,37 @@ export const useUserStore = defineStore({
return this.roles;
},
/** Save modifications of role on the backend
* @param role role to save
* @throws Probably an AxiosError if request failed
*/
async updateRole(role: FG.Role) {
try {
await api.put(`/roles/${role.id}`, role);
} catch (error) {
console.warn(error);
}
this._updatePermission(role);
},
await api.put(`/roles/${role.id}`, role);
_updatePermission(role: FG.Role) {
const idx = this.roles.findIndex((r) => r.id === role.id);
if (idx != -1) this.roles[idx] = role;
this._dirty_roles = true;
},
/** Create a new role
* @param role Role to create (ID not set)
* @returns Created role (ID set)
* @throws Probably an AxiosError if request failed
*/
async newRole(role: FG.Role) {
const { data } = await api.post<FG.Role>('/roles', role);
this.roles.push(data);
return data;
},
/** Delete a role
* @param role Role or ID of role to delete
* @throws Probably an AxiosError if request failed (409 if role still in use)
*/
async deleteRole(role: FG.Role | number) {
await api.delete(`/roles/${typeof role === 'number' ? role : role.id}`);
this.roles = this.roles.filter((r) => r.id !== (typeof role == 'number' ? role : role.id));
if (typeof role === 'object') role = role.id;
await api.delete(`/roles/${role}`);
this.roles = this.roles.filter((r) => r.id !== role);
},
},
});