Tried using front end to translate push notifications, not a good idea

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2021-05-07 17:18:58 +02:00
parent bdae03fc52
commit 4a53e7518a
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
16 changed files with 523 additions and 290 deletions

View File

@ -55,6 +55,7 @@ import RouteName from "../../router/name";
import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { mixins } from "vue-class-component";
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -67,35 +68,9 @@ export default class DiscussionActivityItem extends mixins(ActivityMixin) {
ActivityDiscussionSubject = ActivityDiscussionSubject;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityDiscussionSubject.DISCUSSION_CREATED:
if (this.isAuthorCurrentActor) {
return "You created the discussion {discussion}.";
}
return "{profile} created the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_REPLIED:
if (this.isAuthorCurrentActor) {
return "You replied to the discussion {discussion}.";
}
return "{profile} replied to the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_RENAMED:
if (this.isAuthorCurrentActor) {
return "You renamed the discussion from {old_discussion} to {discussion}.";
}
return "{profile} renamed the discussion from {old_discussion} to {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_ARCHIVED:
if (this.isAuthorCurrentActor) {
return "You archived the discussion {discussion}.";
}
return "{profile} archived the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_DELETED:
if (this.isAuthorCurrentActor) {
return "You deleted the discussion {discussion}.";
}
return "{profile} deleted the discussion {discussion}.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
});
}
get iconColor(): string | undefined {

View File

@ -44,6 +44,7 @@ import { Component } from "vue-property-decorator";
import RouteName from "../../router/name";
import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -56,36 +57,9 @@ export default class EventActivityItem extends mixins(ActivityMixin) {
RouteName = RouteName;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityEventSubject.EVENT_CREATED:
if (this.isAuthorCurrentActor) {
return "You created the event {event}.";
}
return "The event {event} was created by {profile}.";
case ActivityEventSubject.EVENT_UPDATED:
if (this.isAuthorCurrentActor) {
return "You updated the event {event}.";
}
return "The event {event} was updated by {profile}.";
case ActivityEventSubject.EVENT_DELETED:
if (this.isAuthorCurrentActor) {
return "You deleted the event {event}.";
}
return "The event {event} was deleted by {profile}.";
case ActivityEventCommentSubject.COMMENT_POSTED:
if (this.subjectParams.comment_reply_to) {
if (this.isAuthorCurrentActor) {
return "You replied to a comment on the event {event}.";
}
return "{profile} replied to a comment on the event {event}.";
}
if (this.isAuthorCurrentActor) {
return "You posted a comment on the event {event}.";
}
return "{profile} posted a comment on the event {event}.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
});
}
get iconColor(): string | undefined {

View File

@ -77,6 +77,7 @@ import RouteName from "../../router/name";
import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { mixins } from "vue-class-component";
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -89,20 +90,9 @@ export default class GroupActivityItem extends mixins(ActivityMixin) {
ActivityGroupSubject = ActivityGroupSubject;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityGroupSubject.GROUP_CREATED:
if (this.isAuthorCurrentActor) {
return "You created the group {group}.";
}
return "{profile} created the group {group}.";
case ActivityGroupSubject.GROUP_UPDATED:
if (this.isAuthorCurrentActor) {
return "You updated the group {group}.";
}
return "{profile} updated the group {group}.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
});
}
get iconColor(): string | undefined {

View File

@ -42,19 +42,13 @@
</template>
<script lang="ts">
import { usernameWithDomain } from "@/types/actor";
import { ActivityMemberSubject, MemberRole } from "@/types/enums";
import { ActivityMemberSubject } from "@/types/enums";
import { Component } from "vue-property-decorator";
import RouteName from "../../router/name";
import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { mixins } from "vue-class-component";
export const MEMBER_ROLE_VALUE: Record<string, number> = {
[MemberRole.MEMBER]: 20,
[MemberRole.MODERATOR]: 50,
[MemberRole.ADMINISTRATOR]: 90,
[MemberRole.CREATOR]: 100,
};
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -67,49 +61,10 @@ export default class MemberActivityItem extends mixins(ActivityMixin) {
ActivityMemberSubject = ActivityMemberSubject;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityMemberSubject.MEMBER_REQUEST:
if (this.isAuthorCurrentActor) {
return "You requested to join the group.";
}
return "{member} requested to join the group.";
case ActivityMemberSubject.MEMBER_INVITED:
if (this.isAuthorCurrentActor) {
return "You invited {member}.";
}
return "{member} was invited by {profile}.";
case ActivityMemberSubject.MEMBER_ADDED:
if (this.isAuthorCurrentActor) {
return "You added the member {member}.";
}
return "{profile} added the member {member}.";
case ActivityMemberSubject.MEMBER_JOINED:
return "{member} joined the group.";
case ActivityMemberSubject.MEMBER_UPDATED:
if (this.subjectParams.member_role && this.subjectParams.old_role) {
return this.roleUpdate;
}
if (this.isAuthorCurrentActor) {
return "You updated the member {member}.";
}
return "{profile} updated the member {member}.";
case ActivityMemberSubject.MEMBER_REMOVED:
if (this.isAuthorCurrentActor) {
return "You excluded member {member}.";
}
return "{profile} excluded member {member}.";
case ActivityMemberSubject.MEMBER_QUIT:
return "{profile} quit the group.";
case ActivityMemberSubject.MEMBER_REJECTED_INVITATION:
return "{member} rejected the invitation to join the group.";
case ActivityMemberSubject.MEMBER_ACCEPTED_INVITATION:
if (this.isAuthorCurrentActor) {
return "You accepted the invitation to join the group.";
}
return "{member} accepted the invitation to join the group.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
isObjectMemberCurrentActor: this.isObjectMemberCurrentActor,
});
}
get icon(): string {
@ -149,77 +104,6 @@ export default class MemberActivityItem extends mixins(ActivityMixin) {
}
}
get roleUpdate(): string | undefined {
if (
Object.keys(MEMBER_ROLE_VALUE).includes(this.subjectParams.member_role) &&
Object.keys(MEMBER_ROLE_VALUE).includes(this.subjectParams.old_role)
) {
if (
MEMBER_ROLE_VALUE[this.subjectParams.member_role] >
MEMBER_ROLE_VALUE[this.subjectParams.old_role]
) {
switch (this.subjectParams.member_role) {
case MemberRole.MODERATOR:
if (this.isAuthorCurrentActor) {
return "You promoted {member} to moderator.";
}
if (this.isObjectMemberCurrentActor) {
return "You were promoted to moderator by {profile}.";
}
return "{profile} promoted {member} to moderator.";
case MemberRole.ADMINISTRATOR:
if (this.isAuthorCurrentActor) {
return "You promoted {member} to administrator.";
}
if (this.isObjectMemberCurrentActor) {
return "You were promoted to administrator by {profile}.";
}
return "{profile} promoted {member} to administrator.";
default:
if (this.isAuthorCurrentActor) {
return "You promoted the member {member} to an unknown role.";
}
if (this.isObjectMemberCurrentActor) {
return "You were promoted to an unknown role by {profile}.";
}
return "{profile} promoted {member} to an unknown role.";
}
} else {
switch (this.subjectParams.member_role) {
case MemberRole.MODERATOR:
if (this.isAuthorCurrentActor) {
return "You demoted {member} to moderator.";
}
if (this.isObjectMemberCurrentActor) {
return "You were demoted to moderator by {profile}.";
}
return "{profile} demoted {member} to moderator.";
case MemberRole.MEMBER:
if (this.isAuthorCurrentActor) {
return "You demoted {member} to simple member.";
}
if (this.isObjectMemberCurrentActor) {
return "You were demoted to simple member by {profile}.";
}
return "{profile} demoted {member} to simple member.";
default:
if (this.isAuthorCurrentActor) {
return "You demoted the member {member} to an unknown role.";
}
if (this.isObjectMemberCurrentActor) {
return "You were demoted to an unknown role by {profile}.";
}
return "{profile} demoted {member} to an unknown role.";
}
}
} else {
if (this.isAuthorCurrentActor) {
return "You updated the member {member}.";
}
return "{profile} updated the member {member}";
}
}
get isObjectMemberCurrentActor(): boolean {
return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@ -41,6 +41,7 @@ import RouteName from "../../router/name";
import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { mixins } from "vue-class-component";
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -53,25 +54,9 @@ export default class PostActivityItem extends mixins(ActivityMixin) {
ActivityPostSubject = ActivityPostSubject;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityPostSubject.POST_CREATED:
if (this.isAuthorCurrentActor) {
return "You created the post {post}.";
}
return "The post {post} was created by {profile}.";
case ActivityPostSubject.POST_UPDATED:
if (this.isAuthorCurrentActor) {
return "You updated the post {post}.";
}
return "The post {post} was updated by {profile}.";
case ActivityPostSubject.POST_DELETED:
if (this.isAuthorCurrentActor) {
return "You deleted the post {post}.";
}
return "The post {post} was deleted by {profile}.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
});
}
get iconColor(): string | undefined {

View File

@ -52,6 +52,7 @@ import PopoverActorCard from "../Account/PopoverActorCard.vue";
import ActivityMixin from "../../mixins/activity";
import { mixins } from "vue-class-component";
import { Location } from "vue-router";
import { convertActivity } from "@/services/activity-converter";
@Component({
components: {
@ -63,74 +64,10 @@ export default class ResourceActivityItem extends mixins(ActivityMixin) {
RouteName = RouteName;
get translation(): string | undefined {
switch (this.activity.subject) {
case ActivityResourceSubject.RESOURCE_CREATED:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (this.activity?.object?.type === "folder") {
if (this.isAuthorCurrentActor) {
return "You created the folder {resource}.";
}
return "{profile} created the folder {resource}.";
}
if (this.isAuthorCurrentActor) {
return "You created the resource {resource}.";
}
return "{profile} created the resource {resource}.";
case ActivityResourceSubject.RESOURCE_MOVED:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (this.activity?.object?.type === "folder") {
if (this.parentDirectory === null) {
if (this.isAuthorCurrentActor) {
return "You moved the folder {resource} to the root folder.";
}
return "{profile} moved the folder {resource} to the root folder.";
}
if (this.isAuthorCurrentActor) {
return "You moved the folder {resource} into {new_path}.";
}
return "{profile} moved the folder {resource} into {new_path}.";
}
if (this.parentDirectory === null) {
if (this.isAuthorCurrentActor) {
return "You moved the resource {resource} to the root folder.";
}
return "{profile} moved the resource {resource} to the root folder.";
}
if (this.isAuthorCurrentActor) {
return "You moved the resource {resource} into {new_path}.";
}
return "{profile} moved the resource {resource} into {new_path}.";
case ActivityResourceSubject.RESOURCE_UPDATED:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (this.activity?.object?.type === "folder") {
if (this.isAuthorCurrentActor) {
return "You renamed the folder from {old_resource_title} to {resource}.";
}
return "{profile} renamed the folder from {old_resource_title} to {resource}.";
}
if (this.isAuthorCurrentActor) {
return "You renamed the resource from {old_resource_title} to {resource}.";
}
return "{profile} renamed the resource from {old_resource_title} to {resource}.";
case ActivityResourceSubject.RESOURCE_DELETED:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (this.activity?.object?.type === "folder") {
if (this.isAuthorCurrentActor) {
return "You deleted the folder {resource}.";
}
return "{profile} deleted the folder {resource}.";
}
if (this.isAuthorCurrentActor) {
return "You deleted the resource {resource}.";
}
return "{profile} deleted the resource {resource}.";
default:
return undefined;
}
return convertActivity(this.activity, {
isAuthorCurrentActor: this.isAuthorCurrentActor,
parentDirectory: this.parentDirectory,
});
}
get iconColor(): string | undefined {

View File

@ -77,9 +77,14 @@ registerRoute(
);
self.addEventListener("push", async (event: any) => {
console.log("received push", event);
const activity = event.data.json();
console.log("received push", activity);
const template =
convertActivity(activity) || "A push notification has been sent";
const options = {
body: "Ceci est une notification envoyée par Mobilizon !",
body: await translate(template),
icon: "images/notification-flat.png",
vibrate: [100, 50, 100],
data: {
@ -92,11 +97,6 @@ self.addEventListener("push", async (event: any) => {
title: "Go to the site",
icon: "images/checkmark.png",
},
{
action: "close",
title: "Close the notification",
icon: "images/xmark.png",
},
],
};
@ -106,3 +106,69 @@ self.addEventListener("push", async (event: any) => {
self.registration.showNotification("Push Notification", options)
);
});
async function translate(template: string): Promise<string> {
const DEFAULT_LOCALE = "en_US";
let vueI18n = new VueI18n({
locale: DEFAULT_LOCALE, // set locale
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
messages: en, // set locale messages
fallbackLocale: DEFAULT_LOCALE,
formatFallbackMessages: true,
pluralizationRules,
});
vueI18n = await loadLanguageAsync(vueI18n, getLocale());
return vueI18n.t(template) as string;
}
function getLocale(): string {
const language = (
(window.navigator as any).userLanguage || window.navigator.language
).replace(/-/, "_");
return language && Object.prototype.hasOwnProperty.call(langs, language)
? language
: language.split("-")[0];
}
export async function loadLanguageAsync(
i18n: VueI18n,
lang: string
): Promise<VueI18n> {
// If the same language
if (i18n.locale === lang) {
return Promise.resolve(setI18nLanguage(i18n, lang));
}
// If the language hasn't been loaded yet
const newMessages = await import(
/* webpackChunkName: "lang-[request]" */ `@/i18n/${vueI18NfileForLanguage(
lang
)}.json`
);
i18n.setLocaleMessage(lang, newMessages.default);
return setI18nLanguage(i18n, lang);
}
function setI18nLanguage(i18n: VueI18n, lang: string): VueI18n {
i18n.locale = lang;
return i18n;
}
function fileForLanguage(matches: Record<string, string>, lang: string) {
if (Object.prototype.hasOwnProperty.call(matches, lang)) {
return matches[lang];
}
return lang;
}
function vueI18NfileForLanguage(lang: string) {
const matches: Record<string, string> = {
fr: "fr_FR",
en: "en_US",
};
return fileForLanguage(matches, lang);
}

View File

@ -0,0 +1,52 @@
import { IActivity, IPatchedActivity } from "@/types/activity.model";
import { IGroup } from "@/types/actor";
import { IMember } from "@/types/actor/member.model";
import { IDiscussion } from "@/types/discussions";
import { ActivityType } from "@/types/enums";
import { IEvent } from "@/types/event.model";
import { IPost } from "@/types/post.model";
import { IResource } from "@/types/resource";
import { convertDiscussionActivity } from "./activity/discussion";
import { convertEventActivity } from "./activity/event";
import { convertGroupActivity } from "./activity/group";
import { convertMemberActivity } from "./activity/member";
import { convertPostActivity } from "./activity/post";
import { convertResourceActivity } from "./activity/resource";
import { convertActivityOptions, reduceSubjectParams } from "./activity/utils";
export function convertActivity(
activity: IActivity,
options: convertActivityOptions = {}
): string | undefined {
const converter = mapActivityTypeToFunction(activity.type);
const patchedActivity = {
...activity,
subjectParams: reduceSubjectParams(activity),
};
return converter(patchedActivity, options);
}
type activityConverter<T> = (
activity: IPatchedActivity<T>,
options: any
) => string | undefined;
const mapActivityTypeToFunction = (
activityType: string
): activityConverter<any> => {
switch (activityType) {
case ActivityType.EVENT:
return convertEventActivity as activityConverter<IEvent>;
case ActivityType.POST:
return convertPostActivity as activityConverter<IPost>;
case ActivityType.MEMBER:
return convertMemberActivity as activityConverter<IMember>;
case ActivityType.RESOURCE:
return convertResourceActivity as activityConverter<IResource>;
case ActivityType.DISCUSSION:
return convertDiscussionActivity as activityConverter<IDiscussion>;
case ActivityType.GROUP:
return convertGroupActivity as activityConverter<IGroup>;
}
return () => undefined;
};

View File

@ -0,0 +1,39 @@
import { IPatchedActivity } from "@/types/activity.model";
import { IDiscussion } from "@/types/discussions";
import { ActivityDiscussionSubject } from "@/types/enums";
import { convertActivityOptions } from "./utils";
export function convertDiscussionActivity(
activity: IPatchedActivity<IDiscussion>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityDiscussionSubject.DISCUSSION_CREATED:
if (options.isAuthorCurrentActor) {
return "You created the discussion {discussion}.";
}
return "{profile} created the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_REPLIED:
if (options.isAuthorCurrentActor) {
return "You replied to the discussion {discussion}.";
}
return "{profile} replied to the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_RENAMED:
if (options.isAuthorCurrentActor) {
return "You renamed the discussion from {old_discussion} to {discussion}.";
}
return "{profile} renamed the discussion from {old_discussion} to {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_ARCHIVED:
if (options.isAuthorCurrentActor) {
return "You archived the discussion {discussion}.";
}
return "{profile} archived the discussion {discussion}.";
case ActivityDiscussionSubject.DISCUSSION_DELETED:
if (options.isAuthorCurrentActor) {
return "You deleted the discussion {discussion}.";
}
return "{profile} deleted the discussion {discussion}.";
default:
return undefined;
}
}

View File

@ -0,0 +1,43 @@
import { IPatchedActivity } from "@/types/activity.model";
import {
ActivityEventCommentSubject,
ActivityEventSubject,
} from "@/types/enums";
import { IEvent } from "@/types/event.model";
import { convertActivityOptions } from "./utils";
export function convertEventActivity(
activity: IPatchedActivity<IEvent>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityEventSubject.EVENT_CREATED:
if (options.isAuthorCurrentActor) {
return "You created the event {event}.";
}
return "The event {event} was created by {profile}.";
case ActivityEventSubject.EVENT_UPDATED:
if (options.isAuthorCurrentActor) {
return "You updated the event {event}.";
}
return "The event {event} was updated by {profile}.";
case ActivityEventSubject.EVENT_DELETED:
if (options.isAuthorCurrentActor) {
return "You deleted the event {event}.";
}
return "The event {event} was deleted by {profile}.";
case ActivityEventCommentSubject.COMMENT_POSTED:
if (activity.subjectParams.comment_reply_to) {
if (options.isAuthorCurrentActor) {
return "You replied to a comment on the event {event}.";
}
return "{profile} replied to a comment on the event {event}.";
}
if (options.isAuthorCurrentActor) {
return "You posted a comment on the event {event}.";
}
return "{profile} posted a comment on the event {event}.";
default:
return undefined;
}
}

View File

@ -0,0 +1,24 @@
import { IPatchedActivity } from "@/types/activity.model";
import { IGroup } from "@/types/actor";
import { ActivityGroupSubject } from "@/types/enums";
import { convertActivityOptions } from "./utils";
export function convertGroupActivity(
activity: IPatchedActivity<IGroup>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityGroupSubject.GROUP_CREATED:
if (options.isAuthorCurrentActor) {
return "You created the group {group}.";
}
return "{profile} created the group {group}.";
case ActivityGroupSubject.GROUP_UPDATED:
if (options.isAuthorCurrentActor) {
return "You updated the group {group}.";
}
return "{profile} updated the group {group}.";
default:
return undefined;
}
}

View File

@ -0,0 +1,139 @@
import { IPatchedActivity } from "@/types/activity.model";
import { IMember } from "@/types/actor/member.model";
import { ActivityMemberSubject, MemberRole } from "@/types/enums";
import { convertActivityOptions } from "./utils";
export function convertMemberActivity(
activity: IPatchedActivity<IMember>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityMemberSubject.MEMBER_REQUEST:
if (options.isAuthorCurrentActor) {
return "You requested to join the group.";
}
return "{member} requested to join the group.";
case ActivityMemberSubject.MEMBER_INVITED:
if (options.isAuthorCurrentActor) {
return "You invited {member}.";
}
return "{member} was invited by {profile}.";
case ActivityMemberSubject.MEMBER_ADDED:
if (options.isAuthorCurrentActor) {
return "You added the member {member}.";
}
return "{profile} added the member {member}.";
case ActivityMemberSubject.MEMBER_JOINED:
return "{member} joined the group.";
case ActivityMemberSubject.MEMBER_UPDATED:
if (
activity.subjectParams.member_role &&
activity.subjectParams.old_role
) {
return roleUpdate(activity, options);
}
if (options.isAuthorCurrentActor) {
return "You updated the member {member}.";
}
return "{profile} updated the member {member}.";
case ActivityMemberSubject.MEMBER_REMOVED:
if (options.isAuthorCurrentActor) {
return "You excluded member {member}.";
}
return "{profile} excluded member {member}.";
case ActivityMemberSubject.MEMBER_QUIT:
return "{profile} quit the group.";
case ActivityMemberSubject.MEMBER_REJECTED_INVITATION:
return "{member} rejected the invitation to join the group.";
case ActivityMemberSubject.MEMBER_ACCEPTED_INVITATION:
if (options.isAuthorCurrentActor) {
return "You accepted the invitation to join the group.";
}
return "{member} accepted the invitation to join the group.";
default:
return undefined;
}
}
const MEMBER_ROLE_VALUE: Record<string, number> = {
[MemberRole.MEMBER]: 20,
[MemberRole.MODERATOR]: 50,
[MemberRole.ADMINISTRATOR]: 90,
[MemberRole.CREATOR]: 100,
};
function roleUpdate(
activity: IPatchedActivity<IMember>,
options: convertActivityOptions
): string | undefined {
if (
Object.keys(MEMBER_ROLE_VALUE).includes(
activity.subjectParams.member_role
) &&
Object.keys(MEMBER_ROLE_VALUE).includes(activity.subjectParams.old_role)
) {
if (
MEMBER_ROLE_VALUE[activity.subjectParams.member_role] >
MEMBER_ROLE_VALUE[activity.subjectParams.old_role]
) {
switch (activity.subjectParams.member_role) {
case MemberRole.MODERATOR:
if (options.isAuthorCurrentActor) {
return "You promoted {member} to moderator.";
}
if (options.isObjectMemberCurrentActor) {
return "You were promoted to moderator by {profile}.";
}
return "{profile} promoted {member} to moderator.";
case MemberRole.ADMINISTRATOR:
if (options.isAuthorCurrentActor) {
return "You promoted {member} to administrator.";
}
if (options.isObjectMemberCurrentActor) {
return "You were promoted to administrator by {profile}.";
}
return "{profile} promoted {member} to administrator.";
default:
if (options.isAuthorCurrentActor) {
return "You promoted the member {member} to an unknown role.";
}
if (options.isObjectMemberCurrentActor) {
return "You were promoted to an unknown role by {profile}.";
}
return "{profile} promoted {member} to an unknown role.";
}
} else {
switch (activity.subjectParams.member_role) {
case MemberRole.MODERATOR:
if (options.isAuthorCurrentActor) {
return "You demoted {member} to moderator.";
}
if (options.isObjectMemberCurrentActor) {
return "You were demoted to moderator by {profile}.";
}
return "{profile} demoted {member} to moderator.";
case MemberRole.MEMBER:
if (options.isAuthorCurrentActor) {
return "You demoted {member} to simple member.";
}
if (options.isObjectMemberCurrentActor) {
return "You were demoted to simple member by {profile}.";
}
return "{profile} demoted {member} to simple member.";
default:
if (options.isAuthorCurrentActor) {
return "You demoted the member {member} to an unknown role.";
}
if (options.isObjectMemberCurrentActor) {
return "You were demoted to an unknown role by {profile}.";
}
return "{profile} demoted {member} to an unknown role.";
}
}
} else {
if (options.isAuthorCurrentActor) {
return "You updated the member {member}.";
}
return "{profile} updated the member {member}";
}
}

View File

@ -0,0 +1,29 @@
import { IPatchedActivity } from "@/types/activity.model";
import { ActivityPostSubject } from "@/types/enums";
import { IPost } from "@/types/post.model";
import { convertActivityOptions } from "./utils";
export function convertPostActivity(
activity: IPatchedActivity<IPost>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityPostSubject.POST_CREATED:
if (options.isAuthorCurrentActor) {
return "You created the post {post}.";
}
return "The post {post} was created by {profile}.";
case ActivityPostSubject.POST_UPDATED:
if (options.isAuthorCurrentActor) {
return "You updated the post {post}.";
}
return "The post {post} was updated by {profile}.";
case ActivityPostSubject.POST_DELETED:
if (options.isAuthorCurrentActor) {
return "You deleted the post {post}.";
}
return "The post {post} was deleted by {profile}.";
default:
return undefined;
}
}

View File

@ -0,0 +1,70 @@
import { IPatchedActivity } from "@/types/activity.model";
import { ActivityResourceSubject } from "@/types/enums";
import { IResource } from "@/types/resource";
import { convertActivityOptions } from "./utils";
export function convertResourceActivity(
activity: IPatchedActivity<IResource>,
options: convertActivityOptions
): string | undefined {
switch (activity.subject) {
case ActivityResourceSubject.RESOURCE_CREATED:
if (activity?.object?.type === "folder") {
if (options.isAuthorCurrentActor) {
return "You created the folder {resource}.";
}
return "{profile} created the folder {resource}.";
}
if (options.isAuthorCurrentActor) {
return "You created the resource {resource}.";
}
return "{profile} created the resource {resource}.";
case ActivityResourceSubject.RESOURCE_MOVED:
if (activity?.object?.type === "folder") {
if (options.parentDirectory === null) {
if (options.isAuthorCurrentActor) {
return "You moved the folder {resource} to the root folder.";
}
return "{profile} moved the folder {resource} to the root folder.";
}
if (options.isAuthorCurrentActor) {
return "You moved the folder {resource} into {new_path}.";
}
return "{profile} moved the folder {resource} into {new_path}.";
}
if (options.parentDirectory === null) {
if (options.isAuthorCurrentActor) {
return "You moved the resource {resource} to the root folder.";
}
return "{profile} moved the resource {resource} to the root folder.";
}
if (options.isAuthorCurrentActor) {
return "You moved the resource {resource} into {new_path}.";
}
return "{profile} moved the resource {resource} into {new_path}.";
case ActivityResourceSubject.RESOURCE_UPDATED:
if (activity?.object?.type === "folder") {
if (options.isAuthorCurrentActor) {
return "You renamed the folder from {old_resource_title} to {resource}.";
}
return "{profile} renamed the folder from {old_resource_title} to {resource}.";
}
if (options.isAuthorCurrentActor) {
return "You renamed the resource from {old_resource_title} to {resource}.";
}
return "{profile} renamed the resource from {old_resource_title} to {resource}.";
case ActivityResourceSubject.RESOURCE_DELETED:
if (activity?.object?.type === "folder") {
if (options.isAuthorCurrentActor) {
return "You deleted the folder {resource}.";
}
return "{profile} deleted the folder {resource}.";
}
if (options.isAuthorCurrentActor) {
return "You deleted the resource {resource}.";
}
return "{profile} deleted the resource {resource}.";
default:
return undefined;
}
}

View File

@ -0,0 +1,19 @@
import { IActivity } from "@/types/activity.model";
export function reduceSubjectParams(
activity: IActivity
): Record<string, string> {
return activity.subjectParams.reduce(
(acc: Record<string, string>, { key, value }) => {
acc[key] = value;
return acc;
},
{}
);
}
export type convertActivityOptions = {
isAuthorCurrentActor?: boolean;
isObjectMemberCurrentActor?: boolean;
parentDirectory?: string | undefined | null;
};

View File

@ -23,6 +23,7 @@ export type ActivitySubject =
| ActivityGroupSubject
| ActivityEventCommentSubject;
export type IActivityObject = IEvent | IPost | IGroup | IMember | IResource;
export interface IActivity {
id: string;
type: ActivityType;
@ -30,6 +31,12 @@ export interface IActivity {
subjectParams: { key: string; value: string }[];
author: IActor;
group: IGroup;
object: IEvent | IPost | IGroup | IMember | IResource;
object: IActivityObject;
insertedAt: string;
}
export interface IPatchedActivity<T>
extends Omit<IActivity, "subjectParams" | "object"> {
subjectParams: Record<string, string>;
object: T;
}