diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/data/timeline.ts')
-rw-r--r-- | Timeline/ClientApp/src/app/data/timeline.ts | 346 |
1 files changed, 0 insertions, 346 deletions
diff --git a/Timeline/ClientApp/src/app/data/timeline.ts b/Timeline/ClientApp/src/app/data/timeline.ts deleted file mode 100644 index a8875701..00000000 --- a/Timeline/ClientApp/src/app/data/timeline.ts +++ /dev/null @@ -1,346 +0,0 @@ -import axios from 'axios'; -import XRegExp from 'xregexp'; - -import { base64 } from './base64'; -import { apiBaseUrl } from '../config'; -import { User, UserAuthInfo, getCurrentUser, UserWithToken } from './user'; -import { UiLogicError } from '../common'; - -export const kTimelineVisibilities = ['Public', 'Register', 'Private'] as const; - -export type TimelineVisibility = typeof kTimelineVisibilities[number]; - -export const timelineVisibilityTooltipTranslationMap: Record< - TimelineVisibility, - string -> = { - Public: 'timeline.visibilityTooltip.public', - Register: 'timeline.visibilityTooltip.register', - Private: 'timeline.visibilityTooltip.private', -}; - -export interface TimelineInfo { - uniqueId: string; - name: string; - description: string; - owner: User; - visibility: TimelineVisibility; - members: User[]; - _links: { - posts: string; - }; -} - -export interface TimelinePostTextContent { - type: 'text'; - text: string; -} - -export interface TimelinePostImageContent { - type: 'image'; - url: string; -} - -export type TimelinePostContent = - | TimelinePostTextContent - | TimelinePostImageContent; - -export interface TimelinePostInfo { - id: number; - content: TimelinePostContent; - time: Date; - author: User; -} - -export interface CreatePostRequestTextContent { - type: 'text'; - text: string; -} - -export interface CreatePostRequestImageContent { - type: 'image'; - data: Blob; -} - -export type CreatePostRequestContent = - | CreatePostRequestTextContent - | CreatePostRequestImageContent; - -export interface CreatePostRequest { - content: CreatePostRequestContent; - time?: Date; -} - -// TODO: Remove in the future -export interface TimelineChangePropertyRequest { - visibility?: TimelineVisibility; - description?: string; -} - -export interface PersonalTimelineChangePropertyRequest { - visibility?: TimelineVisibility; - description?: string; -} - -export interface OrdinaryTimelineChangePropertyRequest { - // not supported by server now - // name?: string; - visibility?: TimelineVisibility; - description?: string; -} - -//-------------------- begin: internal model -------------------- - -interface RawTimelinePostTextContent { - type: 'text'; - text: string; -} - -interface RawTimelinePostImageContent { - type: 'image'; - url: string; -} - -type RawTimelinePostContent = - | RawTimelinePostTextContent - | RawTimelinePostImageContent; - -interface RawTimelinePostInfo { - id: number; - content: RawTimelinePostContent; - time: string; - author: User; -} - -interface RawCreatePostRequestTextContent { - type: 'text'; - text: string; -} - -interface RawCreatePostRequestImageContent { - type: 'text'; - data: string; -} - -type RawCreatePostRequestContent = - | RawCreatePostRequestTextContent - | RawCreatePostRequestImageContent; - -interface RawCreatePostRequest { - content: RawCreatePostRequestContent; - time?: string; -} - -//-------------------- end: internal model -------------------- - -function processRawTimelinePostInfo( - raw: RawTimelinePostInfo, - token?: string -): TimelinePostInfo { - return { - ...raw, - content: (() => { - if (raw.content.type === 'image' && token != null) { - return { - ...raw.content, - url: raw.content.url + '?token=' + token, - }; - } - return raw.content; - })(), - time: new Date(raw.time), - }; -} - -type TimelineUrlResolver = (name: string) => string; - -export class TimelineServiceTemplate< - TTimeline extends TimelineInfo, - TChangePropertyRequest -> { - private checkUser(): UserWithToken { - const user = getCurrentUser(); - if (user == null) { - throw new UiLogicError('You must login to perform the operation.'); - } - return user; - } - - constructor(private urlResolver: TimelineUrlResolver) {} - - changeProperty( - name: string, - req: TChangePropertyRequest - ): Promise<TTimeline> { - const user = this.checkUser(); - - return axios - .patch<TTimeline>(`${this.urlResolver(name)}?token=${user.token}`, req) - .then((res) => res.data); - } - - fetch(name: string): Promise<TTimeline> { - return axios - .get<TTimeline>(`${this.urlResolver(name)}`) - .then((res) => res.data); - } - - fetchPosts(name: string): Promise<TimelinePostInfo[]> { - const token = getCurrentUser()?.token; - return axios - .get<RawTimelinePostInfo[]>( - token == null - ? `${this.urlResolver(name)}/posts` - : `${this.urlResolver(name)}/posts?token=${token}` - ) - .then((res) => res.data.map((p) => processRawTimelinePostInfo(p, token))); - } - - createPost( - name: string, - request: CreatePostRequest - ): Promise<TimelinePostInfo> { - const user = this.checkUser(); - - const rawReq: Promise<RawCreatePostRequest> = new Promise< - RawCreatePostRequestContent - >((resolve) => { - if (request.content.type === 'image') { - void base64(request.content.data).then((d) => - resolve({ - ...request.content, - data: d, - } as RawCreatePostRequestImageContent) - ); - } else { - resolve(request.content); - } - }).then((content) => { - const rawReq: RawCreatePostRequest = { - content, - }; - if (request.time != null) { - rawReq.time = request.time.toISOString(); - } - return rawReq; - }); - - return rawReq - .then((req) => - axios.post<RawTimelinePostInfo>( - `${this.urlResolver(name)}/posts?token=${user.token}`, - req - ) - ) - .then((res) => processRawTimelinePostInfo(res.data, user.token)); - } - - deletePost(name: string, id: number): Promise<void> { - const user = this.checkUser(); - - return axios.delete( - `${this.urlResolver(name)}/posts/${id}?token=${user.token}` - ); - } - - addMember(name: string, username: string): Promise<void> { - const user = this.checkUser(); - - return axios.put( - `${this.urlResolver(name)}/members/${username}?token=${user.token}` - ); - } - - removeMember(name: string, username: string): Promise<void> { - const user = this.checkUser(); - - return axios.delete( - `${this.urlResolver(name)}/members/${username}?token=${user.token}` - ); - } - - isMemberOf(username: string, timeline: TTimeline): boolean { - return timeline.members.findIndex((m) => m.username == username) >= 0; - } - - hasReadPermission( - user: UserAuthInfo | null | undefined, - timeline: TTimeline - ): boolean { - if (user != null && user.administrator) return true; - - const { visibility } = timeline; - if (visibility === 'Public') { - return true; - } else if (visibility === 'Register') { - if (user != null) return true; - } else if (visibility === 'Private') { - if (user != null && this.isMemberOf(user.username, timeline)) { - return true; - } - } - return false; - } - - hasPostPermission( - user: UserAuthInfo | null | undefined, - timeline: TTimeline - ): boolean { - if (user != null && user.administrator) return true; - - return ( - user != null && - (timeline.owner.username === user.username || - this.isMemberOf(user.username, timeline)) - ); - } - - hasManagePermission( - user: UserAuthInfo | null | undefined, - timeline: TTimeline - ): boolean { - if (user != null && user.administrator) return true; - - return user != null && user.username == timeline.owner.username; - } - - hasModifyPostPermission( - user: UserAuthInfo | null | undefined, - timeline: TTimeline, - post: TimelinePostInfo - ): boolean { - if (user != null && user.administrator) return true; - - return ( - user != null && - (user.username === timeline.owner.username || - user.username === post.author.username) - ); - } -} - -export type PersonalTimelineService = TimelineServiceTemplate< - TimelineInfo, - PersonalTimelineChangePropertyRequest ->; - -export const personalTimelineService: PersonalTimelineService = new TimelineServiceTemplate< - TimelineInfo, - PersonalTimelineChangePropertyRequest ->((name) => `${apiBaseUrl}/timelines/@${name}`); - -export type OrdinaryTimelineService = TimelineServiceTemplate< - TimelineInfo, - OrdinaryTimelineChangePropertyRequest ->; - -export const ordinaryTimelineService: OrdinaryTimelineService = new TimelineServiceTemplate< - TimelineInfo, - TimelineChangePropertyRequest ->((name) => `${apiBaseUrl}/timelines/${name}`); - -const timelineNameReg = XRegExp('^[-_\\p{L}]*$', 'u'); - -export function validateTimelineName(name: string): boolean { - return timelineNameReg.test(name); -} |