//Import dayjs extend import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; dayjs.extend(relativeTime); import { defineStore } from "pinia"; import cookiesHelper from "../helper/cookiesHelper"; import WebSocketEngine from "../websocket/commentWebsocket"; import { CommentPodcast } from "./class/general/comment"; import { useAuthStore } from "./AuthStore"; import { useApiStore } from "./ApiStore"; import stringHelper from "../helper/stringHelper"; import { CommentMessage, CommentsConfig } from "./class/config/commentsConfig"; import classicApi from "../api/classicApi"; import { Podcast } from "./class/general/podcast"; import { ListClassicReturn } from "./class/general/listReturn"; function errorCommentsConfig(): CommentsConfig { return { inherited: false, abuse: { authRequired: true, }, commentLikes: { authRequired: true, dislikeEnabled: false, likeEnabled: false, }, comments: { authRequired: true, commentAllowed: "NONE", defaultState: "PENDING", depth: 2, }, podcastLikes: { authRequired: true, dislikeEnabled: false, likeEnabled: false, }, }; } export interface CommentUser { name: string | null; uuid: string | null; uuidHash: string | null; } interface CommentState { commentInitialized: boolean; commentWebsocketengine: WebSocketEngine | undefined; commentPodcastId?: number; commentQueueName?: string; commentEventToHandle: Array; commentUser?: CommentUser; commentsForPlayer: { [key: number]: Array }; podcastsCommentsConfig: { [key: number]: CommentsConfig }; } export const useCommentStore = defineStore("CommentStore", { state: (): CommentState => ({ commentInitialized: false, commentWebsocketengine: undefined, commentPodcastId: undefined, commentQueueName: undefined, commentEventToHandle: [], commentsForPlayer: {}, podcastsCommentsConfig: {}, }), actions: { async fetchCommentsForPlayer(podcastId: number) { if (!this.commentsForPlayer[podcastId]) { this.commentsForPlayer[podcastId] = []; const size = 50; let first = 0; let keepFetching = true; while (keepFetching) { const data = await classicApi.fetchData>({ api:2, path:"comment/list", parameters:{ first: first, size: size, podcastId: podcastId, sort: "DATE_DESC", hideAnswers: true, state: "VALIDATED", }, isNotAuth:true }); first += size; this.commentsForPlayer[podcastId] = this.commentsForPlayer[ podcastId ].concat(data.result); keepFetching = data.count !== this.commentsForPlayer[podcastId].length; } } return this.commentsForPlayer[podcastId]; }, async digest(message: string) { return Array.from( new Uint8Array( await crypto.subtle.digest( "SHA-1", new TextEncoder().encode(message), ), ), (byte) => byte.toString(16).padStart(2, "0"), ).join(""); }, async initCommentUser() { if (this.commentUser) { return; } const authStore = useAuthStore(); if (authStore.authProfile) { this.commentUser = { name: authStore.authName, uuid: authStore.authProfile.userId, }; return; } let uuid = cookiesHelper.getCookie("comment-octopus-uuid"); if (null === uuid) { uuid = stringHelper.uuidv4(); cookiesHelper.setCookie("comment-octopus-uuid", uuid); } const hash = await this.digest(uuid); this.commentUser = { name: cookiesHelper.getCookie("comment-octopus-name"), uuid: uuid, uuidHash: hash, }; if ("#miniplayer" === this.commentUser?.name) { this.commentUser.name = null; } }, setCommentUser(name: string) { const authStore = useAuthStore(); if (authStore.authProfile || !this.commentUser) { return; } cookiesHelper.setCookie("comment-octopus-name", name); this.commentUser.name = name; }, async getCommentsConfig(podcast: Podcast): Promise { if (this.podcastsCommentsConfig[podcast.podcastId]) { return this.podcastsCommentsConfig[podcast.podcastId]; } try { this.podcastsCommentsConfig[podcast.podcastId] = await classicApi.fetchData({ api: 2, path:"config/podcast/" + podcast.podcastId, }); } catch { try { this.podcastsCommentsConfig[podcast.podcastId] = await classicApi.fetchData({ api: 2, path: "config/emission/" + podcast.emission.emissionId, }); } catch { this.podcastsCommentsConfig[podcast.podcastId] = errorCommentsConfig(); } } return this.podcastsCommentsConfig[podcast.podcastId]; }, resetPodcastsConfig() { this.podcastsCommentsConfig = {}; }, updatePodcastsConfig(podcastId: number, config: CommentsConfig) { this.podcastsCommentsConfig[podcastId] = config; }, getCanPostCommentAllowed( config: CommentsConfig, podcast: Podcast, ): boolean { if ("NONE" === config.comments.commentAllowed) { return false; } const rightsLiveOnly = "LIVE_ONLY" === config.comments.commentAllowed && undefined !== podcast.conferenceId && "READY_TO_RECORD" === podcast.processingStatus; const rightsLiveRecord = "LIVE_AND_REPLAY" === config.comments.commentAllowed && undefined !== podcast.conferenceId; return ( "ALL" === config.comments.commentAllowed || rightsLiveOnly || rightsLiveRecord ); }, getCanPostComment( config: CommentsConfig | undefined, podcast: Podcast | undefined, isAuth: boolean, ): boolean { if (!config || !podcast) { return false; } return ( this.getCanPostCommentAllowed(config, podcast) && (!config.comments.authRequired || (config.comments.authRequired && isAuth)) ); }, getCanReportAbuse( config: CommentsConfig | undefined, isAuth: boolean, ): boolean { if (!config) { return false; } return ( !config.abuse.authRequired || (config.abuse.authRequired && isAuth) ); }, /*-------------------------------------------------------------------------------------------------------------- | | | Initializing state | | | --------------------------------------------------------------------------------------------------------------*/ async initialize() { const apiStore = useApiStore(); const commentUrl = apiStore.commentUrl?? "https://comments.dev2.saooti.org/"; const url = stringHelper.trimChar(commentUrl.replace("https://", ""),"/"); const engine = new WebSocketEngine(url); await engine.initialize(); this.commentWebsocketengine = engine; this.commentInitialized = true; }, /*-------------------------------------------------------------------------------------------------------------- | | | Comments management methods | | | --------------------------------------------------------------------------------------------------------------*/ unsubscribeToEvent() { if (!this.commentWebsocketengine) { return; } if ( this.commentPodcastId && this.commentQueueName && this.commentWebsocketengine.isPodcastCommentEventConnected( this.commentPodcastId, ) ) { this.commentWebsocketengine.unsubscribeToPodcastCommentEventBus( this.commentPodcastId, this.commentQueueName, ); } }, subscribeToEvents() { if (!this.commentWebsocketengine) { return; } if (this.commentPodcastId && this.commentQueueName) { this.commentWebsocketengine.subscribeToPodcastCommentEventBus( this.commentPodcastId, this.commentQueueName, (message) => { this.commentEventToHandleUpdate(message); }, ); } }, async initComments(podcastId: number, organisationId: string) { this.unsubscribeToEvent(); this.commentQueueName = "/topic/comment." + organisationId + "." + podcastId; this.commentPodcastId = podcastId; this.subscribeToEvents(); }, async unsubscribeComments() { this.unsubscribeComments(); this.commentPodcastId = undefined; }, /*-------------------------------------------------------------------------------------------------------------- | | | Managing conference WebSocket Event Received | | | --------------------------------------------------------------------------------------------------------------*/ commentEventHandled() { this.commentEventToHandle.shift(); }, commentEventToHandleUpdate(eventToHandle: { comment: CommentPodcast; type: string; }) { if (eventToHandle) { this.commentEventToHandle.push(eventToHandle); } else { this.commentEventToHandle.splice(0, this.commentEventToHandle.length); } }, }, });