chore: better service method types based on `paths` object
continuous-integration/drone/pr Build is passing Details

Addresses #3199
This commit is contained in:
WofWca 2023-03-22 19:33:22 +04:00
parent 96e2c81b7e
commit 058951f1fd
35 changed files with 336 additions and 215 deletions

View File

@ -6,7 +6,7 @@ import AbstractModel from '@/models/abstractModel'
import type {IAbstract} from '@/modelTypes/IAbstract' import type {IAbstract} from '@/modelTypes/IAbstract'
import type {Right} from '@/constants/rights' import type {Right} from '@/constants/rights'
interface Paths { interface PathsAll {
create : string create : string
get : string get : string
getAll : string getAll : string
@ -14,6 +14,7 @@ interface Paths {
delete : string delete : string
reset?: string reset?: string
} }
type PathsGeneric = Partial<PathsAll>;
function convertObject(o: Record<string, unknown>) { function convertObject(o: Record<string, unknown>) {
if (o instanceof Date) { if (o instanceof Date) {
@ -40,7 +41,39 @@ function prepareParams(params: Record<string, unknown | unknown[]>) {
return objectToSnakeCase(params) return objectToSnakeCase(params)
} }
export default abstract class AbstractService<Model extends IAbstract = IAbstract> { type VarsFromPathTemplate<P extends string> = P extends `${string}{${infer FirstKey}}${infer Rest}`
? [FirstKey, ...VarsFromPathTemplate<Rest>]
: [];
/**
* @example
* type T = ReplacerDictFromPath<'/teams/{teamId}/members/{username}'>;
* const dict: T = {
* teamId: 1,
* username: 'demo',
* }
*/
type ReplacerDictFromPath<P extends string> = Record<
VarsFromPathTemplate<P>[number],
string | number
>
type ReplacerDictOrNeverFromPath<P extends string | undefined | null> =
P extends string
? ReplacerDictFromPath<P>
: never;
/**
* Prohibit the use of `string` as values, i.e. require a more concrete type:
* string literal or template literal.
*/
type EnsureConst<T extends Record<string, string>> = {
[P in keyof T]: string extends T[P] ? never : T[P];
};
export default abstract class AbstractService<
Model extends IAbstract = IAbstract,
// Not sure if the default value makes sense here. Put it only because a non-optional
// param can't go after an optional one.
P extends PathsGeneric = EnsureConst<PathsGeneric>,
> {
///////////////////////////// /////////////////////////////
// Initial variable definitions // Initial variable definitions
@ -49,13 +82,7 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
http http
loading = false loading = false
uploadProgress = 0 uploadProgress = 0
paths: Paths = { paths: P
create: '',
get: '',
getAll: '',
update: '',
delete: '',
}
// This contains the total number of pages and the number of results for the current page // This contains the total number of pages and the number of results for the current page
totalPages = 0 totalPages = 0
resultCount = 0 resultCount = 0
@ -68,7 +95,7 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
* The abstract constructor. * The abstract constructor.
* @param [paths] An object with all paths. * @param [paths] An object with all paths.
*/ */
constructor(paths : Partial<Paths> = {}) { constructor(paths : EnsureConst<P> = ({} as const)) {
this.http = AuthenticatedHTTPFactory() this.http = AuthenticatedHTTPFactory()
// Set the interceptors to process every request // Set the interceptors to process every request
@ -96,7 +123,7 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
return config return config
}) })
Object.assign(this.paths, paths) this.paths = { ...paths } as P
} }
/** /**
@ -267,8 +294,13 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
* @param model The model to use. The request path is built using the values from the model. * @param model The model to use. The request path is built using the values from the model.
* @param params Optional query parameters * @param params Optional query parameters
*/ */
get(model : Model, params = {}) { // TODO refactor: if `paths.get` is undefined, it's better if `get()` method
if (this.paths.get === '') { // is undefined as well, instead of just returning `never`.
get<T extends P['get']>(
model : ReplacerDictOrNeverFromPath<T>,
params = {},
): Promise<T extends string ? Model : never> {
if (!this.paths.get) {
throw new Error('This model is not able to get data.') throw new Error('This model is not able to get data.')
} }
@ -279,7 +311,11 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
* This is a more abstract implementation which only does a get request. * This is a more abstract implementation which only does a get request.
* Services which need more flexibility can use this. * Services which need more flexibility can use this.
*/ */
async getM(url : string, model : Model = new AbstractModel({}), params: Record<string, unknown> = {}) { async getM<T extends string>(
url : T,
model : ReplacerDictFromPath<T>,
params: Record<string, unknown> = {},
) {
const cancel = this.setLoading() const cancel = this.setLoading()
model = this.beforeGet(model) model = this.beforeGet(model)
@ -312,8 +348,14 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
* @param params Optional query parameters * @param params Optional query parameters
* @param page The page to get * @param page The page to get
*/ */
async getAll(model : Model = new AbstractModel({}), params = {}, page = 1): Promise<Model[]> { // TODO refactor: ensure that if `ReplacerDict` is an empty object type then you
if (this.paths.getAll === '') { // can't pass an arbitrary object literal as `model`.
async getAll<T extends P['getAll']>(
model : ReplacerDictOrNeverFromPath<T> = new AbstractModel({}),
params = {},
page = 1,
): Promise<T extends string ? Model[] : never> {
if (!this.paths.getAll) {
throw new Error('This model is not able to get data.') throw new Error('This model is not able to get data.')
} }
@ -342,8 +384,10 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
* Performs a put request to the url specified before * Performs a put request to the url specified before
* @returns {Promise<any | never>} * @returns {Promise<any | never>}
*/ */
async create(model : Model) { async create<T extends P['create']>(
if (this.paths.create === '') { model : Model & ReplacerDictOrNeverFromPath<T>,
): Promise<T extends string ? Model : never> {
if (!this.paths.create) {
throw new Error('This model is not able to create data.') throw new Error('This model is not able to create data.')
} }
@ -384,8 +428,10 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
/** /**
* Performs a post request to the update url * Performs a post request to the update url
*/ */
update(model : Model) { update<T extends P['update']>(
if (this.paths.update === '') { model : Model & ReplacerDictOrNeverFromPath<T>,
): Promise<T extends string ? Model : never> {
if (!this.paths.update) {
throw new Error('This model is not able to update data.') throw new Error('This model is not able to update data.')
} }
@ -396,8 +442,10 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
/** /**
* Performs a delete request to the update url * Performs a delete request to the update url
*/ */
async delete(model : Model) { async delete<T extends P['delete']>(
if (this.paths.delete === '') { model : ReplacerDictOrNeverFromPath<T>,
) {
if (!this.paths.delete) {
throw new Error('This model is not able to delete data.') throw new Error('This model is not able to delete data.')
} }

View File

@ -5,13 +5,15 @@ import type { IAttachment } from '@/modelTypes/IAttachment'
import {downloadBlob} from '@/helpers/downloadBlob' import {downloadBlob} from '@/helpers/downloadBlob'
export default class AttachmentService extends AbstractService<IAttachment> { const paths = {
create: '/tasks/{taskId}/attachments',
getAll: '/tasks/{taskId}/attachments',
delete: '/tasks/{taskId}/attachments/{id}',
} as const
export default class AttachmentService extends AbstractService<IAttachment, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/tasks/{taskId}/attachments',
getAll: '/tasks/{taskId}/attachments',
delete: '/tasks/{taskId}/attachments/{id}',
})
} }
processModel(model: IAttachment) { processModel(model: IAttachment) {

View File

@ -2,13 +2,15 @@ import AbstractService from './abstractService'
import AvatarModel from '@/models/avatar' import AvatarModel from '@/models/avatar'
import type { IAvatar } from '@/modelTypes/IAvatar' import type { IAvatar } from '@/modelTypes/IAvatar'
export default class AvatarService extends AbstractService<IAvatar> { const paths = {
get: '/user/settings/avatar',
update: '/user/settings/avatar',
create: '/user/settings/avatar/upload',
} as const
export default class AvatarService extends AbstractService<IAvatar, typeof paths> {
constructor() { constructor() {
super({ super(paths)
get: '/user/settings/avatar',
update: '/user/settings/avatar',
create: '/user/settings/avatar/upload',
})
} }
modelFactory(data: Partial<IAvatar>) { modelFactory(data: Partial<IAvatar>) {

View File

@ -3,12 +3,14 @@ import BackgroundImageModel from '../models/backgroundImage'
import ProjectModel from '@/models/project' import ProjectModel from '@/models/project'
import type { IBackgroundImage } from '@/modelTypes/IBackgroundImage' import type { IBackgroundImage } from '@/modelTypes/IBackgroundImage'
export default class BackgroundUnsplashService extends AbstractService<IBackgroundImage> { const paths = {
getAll: '/backgrounds/unsplash/search',
update: '/projects/{projectId}/backgrounds/unsplash',
} as const
export default class BackgroundUnsplashService extends AbstractService<IBackgroundImage, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/backgrounds/unsplash/search',
update: '/projects/{projectId}/backgrounds/unsplash',
})
} }
modelFactory(data: Partial<IBackgroundImage>) { modelFactory(data: Partial<IBackgroundImage>) {

View File

@ -4,11 +4,13 @@ import ProjectModel from '@/models/project'
import type { IProject } from '@/modelTypes/IProject' import type { IProject } from '@/modelTypes/IProject'
import type { IFile } from '@/modelTypes/IFile' import type { IFile } from '@/modelTypes/IFile'
export default class BackgroundUploadService extends AbstractService { const paths = {
create: '/projects/{projectId}/backgrounds/upload',
} as const
export default class BackgroundUploadService extends AbstractService<IProject, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/projects/{projectId}/backgrounds/upload',
})
} }
useCreateInterceptor() { useCreateInterceptor() {

View File

@ -3,14 +3,16 @@ import BucketModel from '../models/bucket'
import TaskService from '@/services/task' import TaskService from '@/services/task'
import type { IBucket } from '@/modelTypes/IBucket' import type { IBucket } from '@/modelTypes/IBucket'
export default class BucketService extends AbstractService<IBucket> { const paths = {
getAll: '/projects/{projectId}/buckets',
create: '/projects/{projectId}/buckets',
update: '/projects/{projectId}/buckets/{id}',
delete: '/projects/{projectId}/buckets/{id}',
} as const
export default class BucketService extends AbstractService<IBucket, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/projects/{projectId}/buckets',
create: '/projects/{projectId}/buckets',
update: '/projects/{projectId}/buckets/{id}',
delete: '/projects/{projectId}/buckets/{id}',
})
} }
modelFactory(data: Partial<IBucket>) { modelFactory(data: Partial<IBucket>) {

View File

@ -2,13 +2,15 @@ import CaldavTokenModel from '@/models/caldavToken'
import type {ICaldavToken} from '@/modelTypes/ICaldavToken' import type {ICaldavToken} from '@/modelTypes/ICaldavToken'
import AbstractService from './abstractService' import AbstractService from './abstractService'
export default class CaldavTokenService extends AbstractService<ICaldavToken> { const paths = {
getAll: '/user/settings/token/caldav',
create: '/user/settings/token/caldav',
delete: '/user/settings/token/caldav/{id}',
} as const
export default class CaldavTokenService extends AbstractService<ICaldavToken, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/user/settings/token/caldav',
create: '/user/settings/token/caldav',
delete: '/user/settings/token/caldav/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -1,9 +1,12 @@
import type { IAbstract } from '@/modelTypes/IAbstract'
import AbstractService from './abstractService' import AbstractService from './abstractService'
export default class EmailUpdateService extends AbstractService { const paths = {
update: '/user/settings/email',
} as const
export default class EmailUpdateService extends AbstractService<IAbstract, typeof paths> {
constructor() { constructor() {
super({ super(paths)
update: '/user/settings/email',
})
} }
} }

View File

@ -3,15 +3,17 @@ import LabelModel from '@/models/label'
import type {ILabel} from '@/modelTypes/ILabel' import type {ILabel} from '@/modelTypes/ILabel'
import {colorFromHex} from '@/helpers/color/colorFromHex' import {colorFromHex} from '@/helpers/color/colorFromHex'
export default class LabelService extends AbstractService<ILabel> { const paths = {
create: '/labels',
getAll: '/labels',
get: '/labels/{id}',
update: '/labels/{id}',
delete: '/labels/{id}',
} as const
export default class LabelService extends AbstractService<ILabel, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/labels',
getAll: '/labels',
get: '/labels/{id}',
update: '/labels/{id}',
delete: '/labels/{id}',
})
} }
processModel(label) { processModel(label) {

View File

@ -2,13 +2,15 @@ import AbstractService from './abstractService'
import LabelTask from '@/models/labelTask' import LabelTask from '@/models/labelTask'
import type {ILabelTask} from '@/modelTypes/ILabelTask' import type {ILabelTask} from '@/modelTypes/ILabelTask'
export default class LabelTaskService extends AbstractService<ILabelTask> { const paths = {
create: '/tasks/{taskId}/labels',
getAll: '/tasks/{taskId}/labels',
delete: '/tasks/{taskId}/labels/{labelId}',
} as const
export default class LabelTaskService extends AbstractService<ILabelTask, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/tasks/{taskId}/labels',
getAll: '/tasks/{taskId}/labels',
delete: '/tasks/{taskId}/labels/{labelId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,14 +2,16 @@ import AbstractService from './abstractService'
import LinkShareModel from '@/models/linkShare' import LinkShareModel from '@/models/linkShare'
import type {ILinkShare} from '@/modelTypes/ILinkShare' import type {ILinkShare} from '@/modelTypes/ILinkShare'
export default class LinkShareService extends AbstractService<ILinkShare> { const paths = {
getAll: '/projects/{projectId}/shares',
get: '/projects/{projectId}/shares/{id}',
create: '/projects/{projectId}/shares',
delete: '/projects/{projectId}/shares/{id}',
} as const
export default class LinkShareService extends AbstractService<ILinkShare, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/projects/{projectId}/shares',
get: '/projects/{projectId}/shares/{id}',
create: '/projects/{projectId}/shares',
delete: '/projects/{projectId}/shares/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,14 +2,18 @@ import AbstractService from '../abstractService'
export type MigrationConfig = { code: string } export type MigrationConfig = { code: string }
type Paths = {
update: `/migration/${string}/migrate`
}
// This service builds on top of the abstract service and basically just hides away method names. // This service builds on top of the abstract service and basically just hides away method names.
// It enables migration services to be created with minimal overhead and even better method names. // It enables migration services to be created with minimal overhead and even better method names.
export default class AbstractMigrationService extends AbstractService<MigrationConfig> { export default class AbstractMigrationService extends AbstractService<MigrationConfig, Paths> {
serviceUrlKey = '' serviceUrlKey = ''
constructor(serviceUrlKey: string) { constructor(serviceUrlKey: string) {
super({ super({
update: '/migration/' + serviceUrlKey + '/migrate', update: `/migration/${serviceUrlKey}/migrate`,
}) })
this.serviceUrlKey = serviceUrlKey this.serviceUrlKey = serviceUrlKey
} }

View File

@ -3,15 +3,17 @@ import NamespaceModel from '../models/namespace'
import type {INamespace} from '@/modelTypes/INamespace' import type {INamespace} from '@/modelTypes/INamespace'
import {colorFromHex} from '@/helpers/color/colorFromHex' import {colorFromHex} from '@/helpers/color/colorFromHex'
export default class NamespaceService extends AbstractService<INamespace> { const paths = {
create: '/namespaces',
get: '/namespaces/{id}',
getAll: '/namespaces',
update: '/namespaces/{id}',
delete: '/namespaces/{id}',
} as const
export default class NamespaceService extends AbstractService<INamespace, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/namespaces',
get: '/namespaces/{id}',
getAll: '/namespaces',
update: '/namespaces/{id}',
delete: '/namespaces/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,12 +2,14 @@ import AbstractService from '@/services/abstractService'
import NotificationModel from '@/models/notification' import NotificationModel from '@/models/notification'
import type {INotification} from '@/modelTypes/INotification' import type {INotification} from '@/modelTypes/INotification'
export default class NotificationService extends AbstractService<INotification> { const paths = {
getAll: '/notifications',
update: '/notifications/{id}',
} as const
export default class NotificationService extends AbstractService<INotification, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/notifications',
update: '/notifications/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,10 +2,11 @@ import AbstractService from './abstractService'
import PasswordResetModel from '@/models/passwordReset' import PasswordResetModel from '@/models/passwordReset'
import type {IPasswordReset} from '@/modelTypes/IPasswordReset' import type {IPasswordReset} from '@/modelTypes/IPasswordReset'
export default class PasswordResetService extends AbstractService<IPasswordReset> { const paths = {} as const
export default class PasswordResetService extends AbstractService<IPasswordReset, typeof paths> {
constructor() { constructor() {
super({}) super(paths)
this.paths = { this.paths = {
reset: '/user/password/reset', reset: '/user/password/reset',
requestReset: '/user/password/token', requestReset: '/user/password/token',

View File

@ -1,10 +1,12 @@
import AbstractService from './abstractService' import AbstractService from './abstractService'
import type {IPasswordUpdate} from '@/modelTypes/IPasswordUpdate' import type {IPasswordUpdate} from '@/modelTypes/IPasswordUpdate'
export default class PasswordUpdateService extends AbstractService<IPasswordUpdate> { const paths = {
update: '/user/password',
} as const
export default class PasswordUpdateService extends AbstractService<IPasswordUpdate, typeof paths> {
constructor() { constructor() {
super({ super(paths)
update: '/user/password',
})
} }
} }

View File

@ -4,15 +4,17 @@ import type {IProject} from '@/modelTypes/IProject'
import TaskService from './task' import TaskService from './task'
import {colorFromHex} from '@/helpers/color/colorFromHex' import {colorFromHex} from '@/helpers/color/colorFromHex'
export default class ProjectService extends AbstractService<IProject> { const paths = {
create: '/namespaces/{namespaceId}/projects',
get: '/projects/{id}',
getAll: '/projects',
update: '/projects/{id}',
delete: '/projects/{id}',
} as const
export default class ProjectService extends AbstractService<IProject, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/namespaces/{namespaceId}/projects',
get: '/projects/{id}',
getAll: '/projects',
update: '/projects/{id}',
delete: '/projects/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,11 +2,13 @@ import AbstractService from './abstractService'
import projectDuplicateModel from '@/models/projectDuplicateModel' import projectDuplicateModel from '@/models/projectDuplicateModel'
import type {IProjectDuplicate} from '@/modelTypes/IProjectDuplicate' import type {IProjectDuplicate} from '@/modelTypes/IProjectDuplicate'
export default class ProjectDuplicateService extends AbstractService<IProjectDuplicate> { const paths = {
create: '/projects/{projectId}/duplicate',
} as const
export default class ProjectDuplicateService extends AbstractService<IProjectDuplicate, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/projects/{projectId}/duplicate',
})
} }
beforeCreate(model) { beforeCreate(model) {

View File

@ -1,11 +1,13 @@
import AbstractService from './abstractService' import AbstractService from './abstractService'
import UserModel from '../models/user' import UserModel from '../models/user'
export default class ProjectUserService extends AbstractService { const paths = {
getAll: '/projects/{projectId}/projectusers',
} as const
export default class ProjectUserService extends AbstractService<UserModel, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/projects/{projectId}/projectusers',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -43,14 +43,16 @@ export function isSavedFilter(project: IProject) {
return getSavedFilterIdFromProjectId(project.id) > 0 return getSavedFilterIdFromProjectId(project.id) > 0
} }
export default class SavedFilterService extends AbstractService<ISavedFilter> { const paths = {
get: '/filters/{id}',
create: '/filters',
update: '/filters/{id}',
delete: '/filters/{id}',
} as const
export default class SavedFilterService extends AbstractService<ISavedFilter, typeof paths> {
constructor() { constructor() {
super({ super(paths)
get: '/filters/{id}',
create: '/filters',
update: '/filters/{id}',
delete: '/filters/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,12 +2,14 @@ import AbstractService from '@/services/abstractService'
import SubscriptionModel from '@/models/subscription' import SubscriptionModel from '@/models/subscription'
import type {ISubscription} from '@/modelTypes/ISubscription' import type {ISubscription} from '@/modelTypes/ISubscription'
export default class SubscriptionService extends AbstractService<ISubscription> { const paths = {
create: '/subscriptions/{entity}/{entityId}',
delete: '/subscriptions/{entity}/{entityId}',
} as const
export default class SubscriptionService extends AbstractService<ISubscription, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/subscriptions/{entity}/{entityId}',
delete: '/subscriptions/{entity}/{entityId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -15,15 +15,17 @@ const parseDate = date => {
return null return null
} }
export default class TaskService extends AbstractService<ITask> { const paths = {
create: '/projects/{projectId}',
getAll: '/tasks/all',
get: '/tasks/{id}',
update: '/tasks/{id}',
delete: '/tasks/{id}',
} as const
export default class TaskService extends AbstractService<ITask, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/projects/{projectId}',
getAll: '/tasks/all',
get: '/tasks/{id}',
update: '/tasks/{id}',
delete: '/tasks/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,12 +2,14 @@ import AbstractService from './abstractService'
import TaskAssigneeModel from '@/models/taskAssignee' import TaskAssigneeModel from '@/models/taskAssignee'
import type {ITaskAssignee} from '@/modelTypes/ITaskAssignee' import type {ITaskAssignee} from '@/modelTypes/ITaskAssignee'
export default class TaskAssigneeService extends AbstractService<ITaskAssignee> { const paths = {
create: '/tasks/{taskId}/assignees',
delete: '/tasks/{taskId}/assignees/{userId}',
} as const
export default class TaskAssigneeService extends AbstractService<ITaskAssignee, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/tasks/{taskId}/assignees',
delete: '/tasks/{taskId}/assignees/{userId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -14,11 +14,13 @@ export interface GetAllTasksParams {
filter_include_nulls: boolean, filter_include_nulls: boolean,
} }
export default class TaskCollectionService extends AbstractService<ITask> { const paths = {
getAll: '/projects/{projectId}/tasks',
} as const
export default class TaskCollectionService extends AbstractService<ITask, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/projects/{projectId}/tasks',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,15 +2,17 @@ import AbstractService from './abstractService'
import TaskCommentModel from '@/models/taskComment' import TaskCommentModel from '@/models/taskComment'
import type {ITaskComment} from '@/modelTypes/ITaskComment' import type {ITaskComment} from '@/modelTypes/ITaskComment'
export default class TaskCommentService extends AbstractService<ITaskComment> { const paths = {
create: '/tasks/{taskId}/comments',
getAll: '/tasks/{taskId}/comments',
get: '/tasks/{taskId}/comments/{id}',
update: '/tasks/{taskId}/comments/{id}',
delete: '/tasks/{taskId}/comments/{id}',
} as const
export default class TaskCommentService extends AbstractService<ITaskComment, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/tasks/{taskId}/comments',
getAll: '/tasks/{taskId}/comments',
get: '/tasks/{taskId}/comments/{id}',
update: '/tasks/{taskId}/comments/{id}',
delete: '/tasks/{taskId}/comments/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,12 +2,14 @@ import AbstractService from './abstractService'
import TaskRelationModel from '@/models/taskRelation' import TaskRelationModel from '@/models/taskRelation'
import type {ITaskRelation} from '@/modelTypes/ITaskRelation' import type {ITaskRelation} from '@/modelTypes/ITaskRelation'
export default class TaskRelationService extends AbstractService<ITaskRelation> { const paths = {
create: '/tasks/{taskId}/relations',
delete: '/tasks/{taskId}/relations/{relationKind}/{otherTaskId}',
} as const
export default class TaskRelationService extends AbstractService<ITaskRelation, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/tasks/{taskId}/relations',
delete: '/tasks/{taskId}/relations/{relationKind}/{otherTaskId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,15 +2,17 @@ import AbstractService from './abstractService'
import TeamModel from '@/models/team' import TeamModel from '@/models/team'
import type {ITeam} from '@/modelTypes/ITeam' import type {ITeam} from '@/modelTypes/ITeam'
export default class TeamService extends AbstractService<ITeam> { const paths = {
create: '/teams',
get: '/teams/{id}',
getAll: '/teams',
update: '/teams/{id}',
delete: '/teams/{id}',
} as const
export default class TeamService extends AbstractService<ITeam, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/teams',
get: '/teams/{id}',
getAll: '/teams',
update: '/teams/{id}',
delete: '/teams/{id}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,13 +2,15 @@ import AbstractService from './abstractService'
import TeamMemberModel from '@/models/teamMember' import TeamMemberModel from '@/models/teamMember'
import type {ITeamMember} from '@/modelTypes/ITeamMember' import type {ITeamMember} from '@/modelTypes/ITeamMember'
export default class TeamMemberService extends AbstractService<ITeamMember> { const paths = {
create: '/teams/{teamId}/members',
delete: '/teams/{teamId}/members/{username}',
update: '/teams/{teamId}/members/{username}/admin',
} as const
export default class TeamMemberService extends AbstractService<ITeamMember, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/teams/{teamId}/members',
delete: '/teams/{teamId}/members/{username}',
update: '/teams/{teamId}/members/{username}/admin',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -3,14 +3,16 @@ import TeamNamespaceModel from '@/models/teamNamespace'
import type {ITeamNamespace} from '@/modelTypes/ITeamNamespace' import type {ITeamNamespace} from '@/modelTypes/ITeamNamespace'
import TeamModel from '@/models/team' import TeamModel from '@/models/team'
export default class TeamNamespaceService extends AbstractService<ITeamNamespace> { const paths = {
create: '/namespaces/{namespaceId}/teams',
getAll: '/namespaces/{namespaceId}/teams',
update: '/namespaces/{namespaceId}/teams/{teamId}',
delete: '/namespaces/{namespaceId}/teams/{teamId}',
} as const
export default class TeamNamespaceService extends AbstractService<ITeamNamespace, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/namespaces/{namespaceId}/teams',
getAll: '/namespaces/{namespaceId}/teams',
update: '/namespaces/{namespaceId}/teams/{teamId}',
delete: '/namespaces/{namespaceId}/teams/{teamId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -3,14 +3,16 @@ import TeamProjectModel from '@/models/teamProject'
import type {ITeamProject} from '@/modelTypes/ITeamProject' import type {ITeamProject} from '@/modelTypes/ITeamProject'
import TeamModel from '@/models/team' import TeamModel from '@/models/team'
export default class TeamProjectService extends AbstractService<ITeamProject> { const paths = {
create: '/projects/{projectId}/teams',
getAll: '/projects/{projectId}/teams',
update: '/projects/{projectId}/teams/{teamId}',
delete: '/projects/{projectId}/teams/{teamId}',
} as const
export default class TeamProjectService extends AbstractService<ITeamProject, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/projects/{projectId}/teams',
getAll: '/projects/{projectId}/teams',
update: '/projects/{projectId}/teams/{teamId}',
delete: '/projects/{projectId}/teams/{teamId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,13 +2,18 @@ import AbstractService from './abstractService'
import TotpModel from '@/models/totp' import TotpModel from '@/models/totp'
import type {ITotp} from '@/modelTypes/ITotp' import type {ITotp} from '@/modelTypes/ITotp'
export default class TotpService extends AbstractService<ITotp> { const urlPrefix = '/user/settings/totp' as const
urlPrefix = '/user/settings/totp' type Paths = {
get: typeof urlPrefix
}
export default class TotpService extends AbstractService<ITotp, Paths> {
urlPrefix = urlPrefix
constructor() { constructor() {
super({}) super({
get: urlPrefix,
this.paths.get = this.urlPrefix })
} }
modelFactory(data) { modelFactory(data) {

View File

@ -2,11 +2,13 @@ import AbstractService from './abstractService'
import UserModel from '@/models/user' import UserModel from '@/models/user'
import type {IUser} from '@/modelTypes/IUser' import type {IUser} from '@/modelTypes/IUser'
export default class UserService extends AbstractService<IUser> { const paths = {
getAll: '/users',
} as const
export default class UserService extends AbstractService<IUser, typeof paths> {
constructor() { constructor() {
super({ super(paths)
getAll: '/users',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -3,14 +3,16 @@ import UserNamespaceModel from '@/models/userNamespace'
import type {IUserNamespace} from '@/modelTypes/IUserNamespace' import type {IUserNamespace} from '@/modelTypes/IUserNamespace'
import UserModel from '@/models/user' import UserModel from '@/models/user'
export default class UserNamespaceService extends AbstractService<IUserNamespace> { const paths = {
create: '/namespaces/{namespaceId}/users',
getAll: '/namespaces/{namespaceId}/users',
update: '/namespaces/{namespaceId}/users/{userId}',
delete: '/namespaces/{namespaceId}/users/{userId}',
} as const
export default class UserNamespaceService extends AbstractService<IUserNamespace, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/namespaces/{namespaceId}/users',
getAll: '/namespaces/{namespaceId}/users',
update: '/namespaces/{namespaceId}/users/{userId}',
delete: '/namespaces/{namespaceId}/users/{userId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -3,14 +3,16 @@ import UserProjectModel from '@/models/userProject'
import type {IUserProject} from '@/modelTypes/IUserProject' import type {IUserProject} from '@/modelTypes/IUserProject'
import UserModel from '@/models/user' import UserModel from '@/models/user'
export default class UserProjectService extends AbstractService<IUserProject> { const paths = {
create: '/projects/{projectId}/users',
getAll: '/projects/{projectId}/users',
update: '/projects/{projectId}/users/{userId}',
delete: '/projects/{projectId}/users/{userId}',
} as const
export default class UserProjectService extends AbstractService<IUserProject, typeof paths> {
constructor() { constructor() {
super({ super(paths)
create: '/projects/{projectId}/users',
getAll: '/projects/{projectId}/users',
update: '/projects/{projectId}/users/{userId}',
delete: '/projects/{projectId}/users/{userId}',
})
} }
modelFactory(data) { modelFactory(data) {

View File

@ -1,10 +1,12 @@
import type {IUserSettings} from '@/modelTypes/IUserSettings' import type {IUserSettings} from '@/modelTypes/IUserSettings'
import AbstractService from './abstractService' import AbstractService from './abstractService'
export default class UserSettingsService extends AbstractService<IUserSettings> { const paths = {
update: '/user/settings/general',
} as const
export default class UserSettingsService extends AbstractService<IUserSettings, typeof paths> {
constructor() { constructor() {
super({ super(paths)
update: '/user/settings/general',
})
} }
} }