Compare commits
	
		
			No commits in common. "b2c70a66573caafb21a530b2a4aa40b559969e6b" and "8e552ba5088d8bdda91e3256c7d7d06a6dbd8b4b" have entirely different histories.
		
	
	
		
			b2c70a6657
			...
			8e552ba508
		
	
		| 
						 | 
					@ -70,11 +70,10 @@ export const useMainStore = defineStore({
 | 
				
			||||||
      const userStore = useUserStore();
 | 
					      const userStore = useUserStore();
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        const { data } = await api.post<FG.Session>('/auth', { userid, password });
 | 
					        const { data } = await api.post<FG.Session>('/auth', { userid, password });
 | 
				
			||||||
        this.session = fixSession(data);
 | 
					 | 
				
			||||||
        this.user = await userStore.getUser(data.userid, true);
 | 
					        this.user = await userStore.getUser(data.userid, true);
 | 
				
			||||||
 | 
					        this.session = fixSession(data);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
      } catch ({ response }) {
 | 
					      } catch ({ response }) {
 | 
				
			||||||
        this.handleLoggedOut();
 | 
					 | 
				
			||||||
        return (<AxiosResponse | undefined>response)?.status || false;
 | 
					        return (<AxiosResponse | undefined>response)?.status || false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,153 +6,86 @@ export function fixUser(u?: FG.User) {
 | 
				
			||||||
  return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
 | 
					  return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Check if state is outdated / dirty
 | 
					 | 
				
			||||||
 * Value is considered outdated after 15 minutes
 | 
					 | 
				
			||||||
 * @param updated Time of last updated (in milliseconds see Date.now())
 | 
					 | 
				
			||||||
 * @returns True if outdated, false otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
function isDirty(updated: number) {
 | 
					 | 
				
			||||||
  return Date.now() - updated > 15 * 60 * 1000;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useUserStore = defineStore({
 | 
					export const useUserStore = defineStore({
 | 
				
			||||||
  id: 'users',
 | 
					  id: 'users',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state: () => ({
 | 
					  state: () => ({
 | 
				
			||||||
    roles: [] as FG.Role[],
 | 
					    roles: [] as FG.Role[],
 | 
				
			||||||
 | 
					    users: [] as FG.User[],
 | 
				
			||||||
    permissions: [] as FG.Permission[],
 | 
					    permissions: [] as FG.Permission[],
 | 
				
			||||||
    // list of all users, include deleted ones, use `users` getter for list of active ones
 | 
					    _dirty_users: true,
 | 
				
			||||||
    _users: [] as FG.User[],
 | 
					    _dirty_roles: true,
 | 
				
			||||||
    // Internal flags for deciding if lists need to force-loaded
 | 
					 | 
				
			||||||
    _dirty_users: 0,
 | 
					 | 
				
			||||||
    _dirty_roles: 0,
 | 
					 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getters: {
 | 
					  getters: {},
 | 
				
			||||||
    users(state) {
 | 
					 | 
				
			||||||
      return state._users.filter((u) => !u.deleted);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
    /** Simply filter all users by ID */
 | 
					 | 
				
			||||||
    findUser(userid: string) {
 | 
					    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) {
 | 
					    async getUser(userid: string, force = false) {
 | 
				
			||||||
      const idx = this._users.findIndex((user) => user.userid === userid);
 | 
					      const idx = this.users.findIndex((user) => user.userid === userid);
 | 
				
			||||||
      if (force || idx === -1 || isDirty(this._dirty_users)) {
 | 
					      if (force || this._dirty_users || idx === -1) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
          const { data } = await api.get<FG.User>(`/users/${userid}`);
 | 
					          const { data } = await api.get<FG.User>(`/users/${userid}`);
 | 
				
			||||||
          fixUser(data);
 | 
					          fixUser(data);
 | 
				
			||||||
          if (idx === -1) this._users.push(data);
 | 
					          if (idx === -1) this.users.push(data);
 | 
				
			||||||
          else this._users[idx] = data;
 | 
					          else this.users[idx] = data;
 | 
				
			||||||
          return data;
 | 
					          return data;
 | 
				
			||||||
        } catch (error) {
 | 
					        } catch (error) {
 | 
				
			||||||
          // Ignore 404, throw all other
 | 
					          // Ignore 404, throw all other
 | 
				
			||||||
          if (!isAxiosError(error, 404)) throw error;
 | 
					          if (!isAxiosError(error, 404)) throw error;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } 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) {
 | 
					    async getUsers(force = false) {
 | 
				
			||||||
      if (force || isDirty(this._dirty_users)) {
 | 
					      if (force || this._dirty_users) {
 | 
				
			||||||
        const { data } = await api.get<FG.User[]>('/users');
 | 
					        const { data } = await api.get<FG.User[]>('/users');
 | 
				
			||||||
        data.forEach(fixUser);
 | 
					        data.forEach(fixUser);
 | 
				
			||||||
        this._users = data;
 | 
					        this.users = data;
 | 
				
			||||||
        this._dirty_users = Date.now();
 | 
					        this._dirty_users = false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      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) {
 | 
					    async updateUser(user: FG.User) {
 | 
				
			||||||
      await api.put(`/users/${user.userid}`, 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();
 | 
					      const mainStore = useMainStore();
 | 
				
			||||||
      if (user.userid === mainStore.user?.userid) mainStore.user = user;
 | 
					      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) {
 | 
					    async createUser(user: FG.User) {
 | 
				
			||||||
      const { data } = await api.post<FG.User>('/users', user);
 | 
					      const { data } = await api.post<FG.User>('/users', user);
 | 
				
			||||||
      this._users.push(<FG.User>fixUser(data));
 | 
					      this.users.push(data);
 | 
				
			||||||
      return 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) {
 | 
					    async deleteUser(user: FG.User | string) {
 | 
				
			||||||
      if (typeof user === 'object') user = user.userid;
 | 
					      if (typeof user === 'object') user = user.userid;
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      await api.delete(`/users/${user}`);
 | 
					      await api.delete(`/users/${user}`);
 | 
				
			||||||
      this._users = this._users.filter((u) => u.userid != user);
 | 
					      this.users = this.users.filter(u => u.userid != user);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Upload an avatar for an user
 | 
					    async uploadAvatar(user: FG.User, file: string | File) {
 | 
				
			||||||
     * 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();
 | 
					      const formData = new FormData();
 | 
				
			||||||
      formData.append('file', file);
 | 
					      formData.append('file', file);
 | 
				
			||||||
      await api.post(`/users/${user}/avatar`, formData, {
 | 
					      await api.post(`/users/${user.userid}/avatar`, formData, {
 | 
				
			||||||
        headers: {
 | 
					        headers: {
 | 
				
			||||||
          'Content-Type': 'multipart/form-data',
 | 
					          'Content-Type': 'multipart/form-data',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Delete avatar of an user
 | 
					    async deleteAvatar(user: FG.User) {
 | 
				
			||||||
     * @param user User or ID of user
 | 
					      await api.delete(`/users/${user.userid}/avatar`);
 | 
				
			||||||
     * @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) {
 | 
					    async getPermissions(force = false) {
 | 
				
			||||||
      if (force || this.permissions.length === 0) {
 | 
					      if (force || this.permissions.length === 0) {
 | 
				
			||||||
        const { data } = await api.get<FG.Permission[]>('/roles/permissions');
 | 
					        const { data } = await api.get<FG.Permission[]>('/roles/permissions');
 | 
				
			||||||
| 
						 | 
					@ -161,51 +94,39 @@ export const useUserStore = defineStore({
 | 
				
			||||||
      return this.permissions;
 | 
					      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) {
 | 
					    async getRoles(force = false) {
 | 
				
			||||||
      if (force || isDirty(this._dirty_roles)) {
 | 
					      if (force || this._dirty_roles) {
 | 
				
			||||||
        const { data } = await api.get<FG.Role[]>('/roles');
 | 
					        const { data } = await api.get<FG.Role[]>('/roles');
 | 
				
			||||||
        this.roles = data;
 | 
					        this.roles = data;
 | 
				
			||||||
        this._dirty_roles = Date.now();
 | 
					        this._dirty_roles = false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return this.roles;
 | 
					      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) {
 | 
					    async updateRole(role: FG.Role) {
 | 
				
			||||||
      await api.put(`/roles/${role.id}`, role);
 | 
					      try {
 | 
				
			||||||
 | 
					        await api.put(`/roles/${role.id}`, role);
 | 
				
			||||||
      const idx = this.roles.findIndex((r) => r.id === role.id);
 | 
					      } catch (error) {
 | 
				
			||||||
      if (idx != -1) this.roles[idx] = role;
 | 
					        console.warn(error);
 | 
				
			||||||
      else this._dirty_roles = 0;
 | 
					      }
 | 
				
			||||||
 | 
					      this._updatePermission(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) {
 | 
					    async newRole(role: FG.Role) {
 | 
				
			||||||
      const { data } = await api.post<FG.Role>('/roles', role);
 | 
					      const { data } = await api.post<FG.Role>('/roles', role);
 | 
				
			||||||
      this.roles.push(data);
 | 
					      this.roles.push(data);
 | 
				
			||||||
      return 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) {
 | 
					    async deleteRole(role: FG.Role | number) {
 | 
				
			||||||
      if (typeof role === 'object') role = role.id;
 | 
					      await api.delete(`/roles/${typeof role === 'number' ? role : role.id}`);
 | 
				
			||||||
      await api.delete(`/roles/${role}`);
 | 
					      this.roles = this.roles.filter((r) => r.id !== (typeof role == 'number' ? role : role.id));
 | 
				
			||||||
      this.roles = this.roles.filter((r) => r.id !== role);
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue