diff --git a/config/default.json b/config/default.json index a1e9adf51..77f8b352e 100644 --- a/config/default.json +++ b/config/default.json @@ -23,5 +23,5 @@ "-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIJAIm6LatK5PNiMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzEdMBsGA1UECgwUT3BlbiBXaGlzcGVyIFN5c3RlbXMxHTAbBgNVBAsMFE9w\nZW4gV2hpc3BlciBTeXN0ZW1zMRMwEQYDVQQDDApUZXh0U2VjdXJlMB4XDTEzMDMy\nNTIyMTgzNVoXDTIzMDMyMzIyMTgzNVowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR0wGwYDVQQKDBRP\ncGVuIFdoaXNwZXIgU3lzdGVtczEdMBsGA1UECwwUT3BlbiBXaGlzcGVyIFN5c3Rl\nbXMxEzARBgNVBAMMClRleHRTZWN1cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQDBSWBpOCBDF0i4q2d4jAXkSXUGpbeWugVPQCjaL6qD9QDOxeW1afvf\nPo863i6Crq1KDxHpB36EwzVcjwLkFTIMeo7t9s1FQolAt3mErV2U0vie6Ves+yj6\ngrSfxwIDAcdsKmI0a1SQCZlr3Q1tcHAkAKFRxYNawADyps5B+Zmqcgf653TXS5/0\nIPPQLocLn8GWLwOYNnYfBvILKDMItmZTtEbucdigxEA9mfIvvHADEbteLtVgwBm9\nR5vVvtwrD6CCxI3pgH7EH7kMP0Od93wLisvn1yhHY7FuYlrkYqdkMvWUrKoASVw4\njb69vaeJCUdU+HCoXOSP1PQcL6WenNCHAgMBAAGjUDBOMB0GA1UdDgQWBBQBixjx\nP/s5GURuhYa+lGUypzI8kDAfBgNVHSMEGDAWgBQBixjxP/s5GURuhYa+lGUypzI8\nkDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB+Hr4hC56m0LvJAu1R\nK6NuPDbTMEN7/jMojFHxH4P3XPFfupjR+bkDq0pPOU6JjIxnrD1XD/EVmTTaTVY5\niOheyv7UzJOefb2pLOc9qsuvI4fnaESh9bhzln+LXxtCrRPGhkxA1IMIo3J/s2WF\n/KVYZyciu6b4ubJ91XPAuBNZwImug7/srWvbpk0hq6A6z140WTVSKtJG7EP41kJe\n/oF4usY5J7LPkxK3LWzMJnb5EIJDmRvyH8pyRwWg6Qm6qiGFaI4nL8QU4La1x2en\n4DGXRaLMPRwjELNgQPodR38zoCMuA8gHZfZYYoZ7D7Q1wNUiVHcxuFrEeBaYJbLE\nrwLV\n-----END CERTIFICATE-----\n", "import": false, "serverTrustRoot": "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx", - "defaultPublicChatServer": "https://chat.lokinet.org/" + "defaultPublicChatServer": "http://localhost:8081" } diff --git a/js/models/conversations.js b/js/models/conversations.js index dff8043fa..279a28247 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -2136,18 +2136,19 @@ }); } }, - isModerator() { + isModerator(pubKey) { if (!this.isPublic()) { return false; } - return this.get('modStatus'); + return this.get('moderators').includes(pubKey); }, - async setModStatus(newStatus) { + async setModerators(moderators) { if (!this.isPublic()) { return; } - if (this.get('modStatus') !== newStatus) { - this.set({ modStatus: newStatus }); + // TODO: compare array properly + if (!_.isEqual(this.get('moderators'), moderators)) { + this.set({ moderators }); await window.Signal.Data.updateConversation(this.id, this.attributes, { Conversation: Whisper.Conversation, }); diff --git a/js/models/messages.js b/js/models/messages.js index 8f2283293..9a0c7db7d 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -680,9 +680,12 @@ isP2p: !!this.get('isP2p'), isPublic: !!this.get('isPublic'), isRss: !!this.get('isRss'), + isModerator: + !!this.get('isPublic') && + this.getConversation().isModerator(this.getSource()), isDeletable: !this.get('isPublic') || - this.getConversation().isModerator() || + this.getConversation().isModerator(this.OUR_NUMBER) || this.getSource() === this.OUR_NUMBER, onCopyText: () => this.copyText(), diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 20e061083..f54fde25c 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -7,7 +7,8 @@ const { URL, URLSearchParams } = require('url'); // Can't be less than 1200 if we have unauth'd requests const PUBLICCHAT_MSG_POLL_EVERY = 1.5 * 1000; // 1.5s const PUBLICCHAT_CHAN_POLL_EVERY = 20 * 1000; // 20s -const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 1 second +const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 5s +const PUBLICCHAT_MOD_POLL_EVERY = 5 * 1000; // 1 second // singleton to relay events to libtextsecure/message_receiver class LokiPublicChatAPI extends EventEmitter { @@ -219,7 +220,7 @@ class LokiPublicChannelAPI { this.pollForMessages(); this.pollForDeletions(); this.pollForChannel(); - this.refreshModStatus(); + this.pollForModerators(); } stop() { @@ -306,17 +307,34 @@ class LokiPublicChannelAPI { }; } + // get moderation actions + async pollForModerators() { + try { + await this.pollOnceForModerators(); + } catch (e) { + log.warn(`Error while polling for public chat moderators: ${e}`); + } + if (this.running) { + this.timers.channel = setTimeout(() => { + this.pollForModerators(); + }, PUBLICCHAT_MOD_POLL_EVERY); + } + } + // get moderator status - async refreshModStatus() { + async pollOnceForModerators() { // get moderator status - const res = await this.serverRequest('loki/v1/user_info'); + const res = await this.serverRequest(`loki/v1/channel/${this.channelId}/get_moderators`); + const ourNumber = textsecure.storage.user.getNumber(); // if no problems and we have data - if (!res.err && res.response && res.response.data) { - this.modStatus = res.response.data.moderator_status; + let moderators; + if (!res.err && res.response && res.response.moderators) { + moderators = res.response.moderators; + this.modStatus = moderators.includes(ourNumber); } // if problems, we won't drop moderator status - await this.conversation.setModStatus(this.modStatus); + await this.conversation.setModerators(moderators); // get token info const tokenRes = await this.serverRequest('token'); @@ -328,7 +346,6 @@ class LokiPublicChannelAPI { tokenRes.response.data.user ) { // get our profile name and write it to the network - const ourNumber = textsecure.storage.user.getNumber(); const profileConvo = ConversationController.get(ourNumber); const profileName = profileConvo.getProfileName(); @@ -386,11 +403,11 @@ class LokiPublicChannelAPI { try { await this.pollForChannelOnce(); } catch (e) { - log.warn(`Error while polling for public chat deletions: ${e}`); + log.warn(`Error while polling for public chat room details: ${e}`); } if (this.running) { this.timers.channel = setTimeout(() => { - this.pollForChannelOnce(); + this.pollForChannel(); }, PUBLICCHAT_CHAN_POLL_EVERY); } } diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 8ed5fa4f3..7be336fb2 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -48,6 +48,7 @@ interface LinkPreviewType { export interface Props { disableMenu?: boolean; + isModerator?: boolean; isDeletable: boolean; text?: string; textPending?: boolean; @@ -648,6 +649,7 @@ export class Message extends React.PureComponent { authorPhoneNumber, authorProfileName, collapseMetadata, + isModerator, authorColor, conversationType, direction, @@ -662,6 +664,9 @@ export class Message extends React.PureComponent { return; } + // TODO: Render mod icon? + console.log(isModerator); + return (