forked from potsda.mn/mobilizon
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
d02d62bd0d
|
@ -42,6 +42,7 @@ import { usernameWithDomain } from "@/types/actor";
|
|||
import { formatTimeString } from "@/filters/datetime";
|
||||
import {
|
||||
ActivityEventCommentSubject,
|
||||
ActivityEventParticipantSubject,
|
||||
ActivityEventSubject,
|
||||
} from "@/types/enums";
|
||||
import { computed } from "vue";
|
||||
|
@ -90,6 +91,14 @@ const translation = computed((): string | undefined => {
|
|||
return "You posted a comment on the event {event}.";
|
||||
}
|
||||
return "{profile} posted a comment on the event {event}.";
|
||||
case ActivityEventParticipantSubject.EVENT_NEW_PARTICIPATION:
|
||||
if (isAuthorCurrentActor.value) {
|
||||
return "You joined the event {event}.";
|
||||
}
|
||||
if (props.activity.author.preferredUsername === "anonymous") {
|
||||
return "An anonymous profile joined the event {event}.";
|
||||
}
|
||||
return "{profile} joined the the event {event}.";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ import { EventJoinOptions } from "@/types/enums";
|
|||
import { IParticipant } from "../../types/participant.model";
|
||||
import RouteName from "../../router/name";
|
||||
import { CONFIRM_PARTICIPATION } from "../../graphql/event";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, ref, watchEffect } from "vue";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useHead } from "@vueuse/head";
|
||||
|
@ -90,9 +90,15 @@ const { onDone, onError, mutate } = useMutation<{
|
|||
confirmParticipation: IParticipant;
|
||||
}>(CONFIRM_PARTICIPATION);
|
||||
|
||||
mutate(() => ({
|
||||
token: props.token,
|
||||
}));
|
||||
const participationToken = computed(() => props.token);
|
||||
|
||||
watchEffect(() => {
|
||||
if (participationToken.value) {
|
||||
mutate({
|
||||
token: participationToken.value,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onDone(async ({ data }) => {
|
||||
participation.value = data?.confirmParticipation;
|
||||
|
|
|
@ -70,14 +70,16 @@ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|||
|
||||
const { loggedUser } = useUserSettings();
|
||||
|
||||
const { mutate: doUpdateLocale } = updateLocale();
|
||||
|
||||
onMounted(() => {
|
||||
updateLocale(locale as unknown as string);
|
||||
doUpdateLocale({ locale: locale as unknown as string });
|
||||
doUpdateSetting({ timezone });
|
||||
});
|
||||
|
||||
watch(locale, () => {
|
||||
if (locale.value) {
|
||||
updateLocale(locale.value as string);
|
||||
doUpdateLocale({ locale: locale as unknown as string });
|
||||
saveLocaleData(locale.value as string);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -59,12 +59,8 @@ export async function doUpdateSetting(
|
|||
}));
|
||||
}
|
||||
|
||||
export async function updateLocale(locale: string) {
|
||||
useMutation<{ id: string; locale: string }>(UPDATE_USER_LOCALE, () => ({
|
||||
variables: {
|
||||
locale,
|
||||
},
|
||||
}));
|
||||
export function updateLocale() {
|
||||
return useMutation<{ id: string; locale: string }>(UPDATE_USER_LOCALE);
|
||||
}
|
||||
|
||||
export function registerAccount() {
|
||||
|
|
|
@ -1579,5 +1579,8 @@
|
|||
"Access drafts events": "Access drafts events",
|
||||
"This application will be allowed to list and view your draft events": "This application will be allowed to list and view your draft events",
|
||||
"Access group suggested events": "Access group suggested events",
|
||||
"This application will be allowed to list your suggested group events": "This application will be allowed to list your suggested group events"
|
||||
"This application will be allowed to list your suggested group events": "This application will be allowed to list your suggested group events",
|
||||
"{profile} joined the the event {event}.": "{profile} joined the the event {event}.",
|
||||
"You joined the event {event}.": "You joined the event {event}.",
|
||||
"An anonymous profile joined the event {event}.": "An anonymous profile joined the event {event}."
|
||||
}
|
|
@ -151,7 +151,7 @@
|
|||
"Attending": "Participant⋅e",
|
||||
"Authorize": "Autoriser",
|
||||
"Authorize application": "Autoriser l'application",
|
||||
"Authorized on {authorization_date}": "Authorisée le {authorization_date}",
|
||||
"Authorized on {authorization_date}": "Autorisée le {authorization_date}",
|
||||
"Autorize this application to access your account?": "Autoriser cette application à accéder à votre compte ?",
|
||||
"Avatar": "Avatar",
|
||||
"Back to group list": "Retour à la liste des groupes",
|
||||
|
@ -1575,5 +1575,8 @@
|
|||
"Access drafts events": "Accéder aux événements brouillons",
|
||||
"This application will be allowed to list and view your draft events": "Cetta application sera autorisée à lister et accéder à vos événements brouillons",
|
||||
"Access group suggested events": "Accéder aux événements des groupes suggérés",
|
||||
"This application will be allowed to list your suggested group events": "Cetta application sera autorisée à lister les événements de vos groupes qui vous sont suggérés"
|
||||
"This application will be allowed to list your suggested group events": "Cetta application sera autorisée à lister les événements de vos groupes qui vous sont suggérés",
|
||||
"{profile} joined the the event {event}.": "{profile} a rejoint l'événement {event}.",
|
||||
"You joined the event {event}.": "Vous avez rejoint l'événement {event}.",
|
||||
"An anonymous profile joined the event {event}.": "Un profil anonyme a rejoint l'événement {event}."
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
"Allow all comments from users with accounts": "Pozwalaj na wszystkie komentarze od zalogowanych użytkowników lub użytkowniczek",
|
||||
"Allow registrations": "Pozwól na rejestrację",
|
||||
"An URL to an external ticketing platform": "Adres URL do zewnętrznej platformy sprzedaży biletów",
|
||||
"An anonymous profile joined the event {event}.": "Anonimowy profil przystąpił do wydarzenia {event}.",
|
||||
"An error has occured while refreshing the page.": "Wystąpił błąd podczas odświeżania strony.",
|
||||
"An error has occured. Sorry about that. You may try to reload the page.": "Przepraszamy, ale wystąpił błąd. Możesz spróbować odświeżyć stronę.",
|
||||
"An ethical alternative": "Etyczna alternatywa",
|
||||
|
@ -696,7 +697,7 @@
|
|||
"No group found": "Nie znaleziono grupy",
|
||||
"No group matches the filters": "Żadna grupa nie spełnia kryteriów filtra",
|
||||
"No group member found": "Nie znaleziono żadnego członka ani członkini grupy",
|
||||
"No groups found": "Nie znaleziono grup",
|
||||
"No groups found": "Nie znaleziono grup",
|
||||
"No groups found for {search}": "Nie znaleziono grup dla {search}",
|
||||
"No information": "nie podano",
|
||||
"No instance follows your instance yet.": "Żadna instancja nie obserwuje jeszcze Twojej instancji.",
|
||||
|
@ -1183,7 +1184,7 @@
|
|||
"This user was not found": "Ten użytkownik / użytkowniczka nie została znaleziona",
|
||||
"This website isn't moderated and the data that you enter will be automatically destroyed every day at 00:01 (Paris timezone).": "Ta strona nie jest moderowana i wszelkie dane które wprowadzasz będą automatycznie usuwane każdego dnia o 00:001 (strefa czasowa Paryża).",
|
||||
"This week": "W tym tygodniu",
|
||||
"This weekend": "Ten weekend",
|
||||
"This weekend": "W najbliższy weekend",
|
||||
"This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "Ta opcja usunie/zanonimizuje całą zawartość (wydarzenia, komentarze, wiadomości, deklaracje udziału…) utworzone z tej tożsamości.",
|
||||
"Time in your timezone ({timezone})": "Czas w Twojej strefie czasowej ({timezone})",
|
||||
"Times in your timezone ({timezone})": "Czasy w Twojej strefie czasowej ({timezone})",
|
||||
|
@ -1372,6 +1373,7 @@
|
|||
"You have one event tomorrow.": "Nie masz jutro żadnych wydarzeń | Masz jutro jedno wydarzenie. | Masz jutro {count} wydarzeń",
|
||||
"You haven't interacted with other instances yet.": "Nie wchodziłeś(-aś) jeszcze w interakcje z innymi instancjami.",
|
||||
"You invited {member}.": "Zaprosiłeś(-aś) {member}.",
|
||||
"You joined the event {event}.": "Ty przystąpiłeś(-aś) do wydarzenia {event}.",
|
||||
"You may also:": "Możesz także:",
|
||||
"You may clear all participation information for this device with the buttons below.": "Wszystkie informacje o uczestnictwie zapisane na tym urządzeniu można usunąć przyciskami poniżej.",
|
||||
"You may now close this page or {return_to_the_homepage}.": "Teraz możesz zamknąć tę stronę lub {return_to_the_homepage}.",
|
||||
|
@ -1556,6 +1558,7 @@
|
|||
"{profile} demoted {member} to moderator.": "{profile} zdegradował(a)(o) {member} do roli moderatora(-ki).",
|
||||
"{profile} demoted {member} to simple member.": "{profile} zdegradował(a)(o) {member} do roli zwykłego członka / zwykłej członkini.",
|
||||
"{profile} excluded member {member}.": "{profile} wykluczył(a)(o) członka / członkinię {member}.",
|
||||
"{profile} joined the the event {event}.": "Profil {profile} przystąpił do wydarzenia {event}.",
|
||||
"{profile} moved the folder {resource} into {new_path}.": "Katalog {resource} został przeniesiony do {new_path} przez {profile}.",
|
||||
"{profile} moved the folder {resource} to the root folder.": "Katalog {resource} został przeniesiony do katalogu głównego przez {profile}.",
|
||||
"{profile} moved the resource {resource} into {new_path}.": "Zasób {resource} został przeniesiony do {new_path} przez {profile}.",
|
||||
|
|
|
@ -32,9 +32,8 @@ export async function subscribeUserToPush(): Promise<PushSubscription | null> {
|
|||
};
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
try {
|
||||
const pushSubscription = await registration.pushManager.subscribe(
|
||||
subscribeOptions
|
||||
);
|
||||
const pushSubscription =
|
||||
await registration.pushManager.subscribe(subscribeOptions);
|
||||
console.debug("Received PushSubscription: ", pushSubscription);
|
||||
resolve(pushSubscription);
|
||||
} catch (e) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { IMember } from "./actor/member.model";
|
|||
import {
|
||||
ActivityDiscussionSubject,
|
||||
ActivityEventCommentSubject,
|
||||
ActivityEventParticipantSubject,
|
||||
ActivityEventSubject,
|
||||
ActivityGroupSubject,
|
||||
ActivityMemberSubject,
|
||||
|
@ -21,7 +22,8 @@ export type ActivitySubject =
|
|||
| ActivityResourceSubject
|
||||
| ActivityDiscussionSubject
|
||||
| ActivityGroupSubject
|
||||
| ActivityEventCommentSubject;
|
||||
| ActivityEventCommentSubject
|
||||
| ActivityEventParticipantSubject;
|
||||
|
||||
export interface IActivity {
|
||||
id: string;
|
||||
|
|
|
@ -200,6 +200,10 @@ export enum ActivityEventCommentSubject {
|
|||
COMMENT_POSTED = "comment_posted",
|
||||
}
|
||||
|
||||
export enum ActivityEventParticipantSubject {
|
||||
EVENT_NEW_PARTICIPATION = "event_new_participation",
|
||||
}
|
||||
|
||||
export enum ActivityPostSubject {
|
||||
POST_CREATED = "post_created",
|
||||
POST_UPDATED = "post_updated",
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="">
|
||||
<o-field :label="t('Status')" horizontal label-for="role-select">
|
||||
<o-select v-model="role" id="role-select">
|
||||
<option :value="null">
|
||||
<option value="EVERYTHING">
|
||||
{{ t("Everything") }}
|
||||
</option>
|
||||
<option :value="ParticipantRole.CREATOR">
|
||||
|
@ -303,17 +303,15 @@ const participantsExportFormats = useParticipantsExportFormats();
|
|||
const ellipsize = (text?: string) =>
|
||||
text && text.substring(0, MESSAGE_ELLIPSIS_LENGTH).concat("…");
|
||||
|
||||
// metaInfo() {
|
||||
// return {
|
||||
// title: this.t("Participants") as string,
|
||||
// };
|
||||
// },
|
||||
const eventId = computed(() => props.eventId);
|
||||
|
||||
const ParticipantAllRoles = { ...ParticipantRole, EVERYTHING: "EVERYTHING" };
|
||||
|
||||
const page = useRouteQuery("page", 1, integerTransformer);
|
||||
const role = useRouteQuery(
|
||||
"role",
|
||||
ParticipantRole.PARTICIPANT,
|
||||
enumTransformer(ParticipantRole)
|
||||
"EVERYTHING",
|
||||
enumTransformer(ParticipantAllRoles)
|
||||
);
|
||||
|
||||
const checkedRows = ref<IParticipant[]>([]);
|
||||
|
@ -325,10 +323,10 @@ const { result: participantsResult, loading: participantsLoading } = useQuery<{
|
|||
}>(
|
||||
PARTICIPANTS,
|
||||
() => ({
|
||||
uuid: props.eventId,
|
||||
uuid: eventId.value,
|
||||
page: page.value,
|
||||
limit: PARTICIPANTS_PER_PAGE,
|
||||
roles: role.value,
|
||||
roles: role.value === "EVERYTHING" ? undefined : role.value,
|
||||
}),
|
||||
() => ({
|
||||
enabled:
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<o-select
|
||||
:loading="loadingTimezones || loadingUserSettings"
|
||||
v-model="$i18n.locale"
|
||||
@update:modelValue="updateLanguage"
|
||||
:placeholder="t('Select a language')"
|
||||
id="setting-language"
|
||||
>
|
||||
|
@ -147,7 +148,7 @@ import RouteName from "../../router/name";
|
|||
import { AddressSearchType } from "@/types/enums";
|
||||
import { Address, IAddress } from "@/types/address.model";
|
||||
import { useTimezones } from "@/composition/apollo/config";
|
||||
import { useUserSettings } from "@/composition/apollo/user";
|
||||
import { useUserSettings, updateLocale } from "@/composition/apollo/user";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { computed, defineAsyncComponent, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
@ -172,6 +173,12 @@ useHead({
|
|||
const theme = ref(localStorage.getItem("theme"));
|
||||
const systemTheme = ref(!("theme" in localStorage));
|
||||
|
||||
const { mutate: doUpdateLocale } = updateLocale();
|
||||
|
||||
const updateLanguage = (newLocale: string) => {
|
||||
doUpdateLocale({ locale: newLocale });
|
||||
};
|
||||
|
||||
watch(systemTheme, (newSystemTheme) => {
|
||||
console.debug("changing system theme", newSystemTheme);
|
||||
if (newSystemTheme) {
|
||||
|
|
|
@ -82,6 +82,11 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Accept do
|
|||
)
|
||||
|
||||
Scheduler.trigger_notifications_for_participant(participant)
|
||||
|
||||
Mobilizon.Service.Activity.Participant.insert_activity(participant,
|
||||
subject: "event_new_participation"
|
||||
)
|
||||
|
||||
participant_as_data = Convertible.model_to_as(participant)
|
||||
audience = Audience.get_audience(participant)
|
||||
|
||||
|
|
|
@ -224,6 +224,10 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Events do
|
|||
cond do
|
||||
Mobilizon.Events.get_default_participant_role(event) == :participant &&
|
||||
role == :participant ->
|
||||
Mobilizon.Service.Activity.Participant.insert_activity(participant,
|
||||
subject: "event_new_participation"
|
||||
)
|
||||
|
||||
{:accept,
|
||||
Actions.Accept.accept(
|
||||
:join,
|
||||
|
|
|
@ -6,6 +6,7 @@ defmodule Mobilizon.GraphQL.Resolvers.PushSubscription do
|
|||
alias Mobilizon.Storage.Page
|
||||
alias Mobilizon.Users
|
||||
alias Mobilizon.Users.{PushSubscription, User}
|
||||
import Mobilizon.Web.Gettext
|
||||
|
||||
@doc """
|
||||
List all of an user's registered push subscriptions
|
||||
|
@ -33,6 +34,19 @@ defmodule Mobilizon.GraphQL.Resolvers.PushSubscription do
|
|||
{:ok, %PushSubscription{}} ->
|
||||
{:ok, "OK"}
|
||||
|
||||
{:error,
|
||||
%Ecto.Changeset{
|
||||
errors: [
|
||||
digest:
|
||||
{"has already been taken",
|
||||
[
|
||||
constraint: :unique,
|
||||
constraint_name: "user_push_subscriptions_user_id_digest_index"
|
||||
]}
|
||||
]
|
||||
}} ->
|
||||
{:error, dgettext("errors", "The same push subscription has already been registered")}
|
||||
|
||||
{:error, err} ->
|
||||
require Logger
|
||||
Logger.error(inspect(err))
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Mobilizon.GraphQL.Schema.Users.PushSubscription do
|
|||
"""
|
||||
use Absinthe.Schema.Notation
|
||||
alias Mobilizon.GraphQL.Resolvers.PushSubscription
|
||||
alias Mobilizon.Users.User
|
||||
|
||||
# object :push_subscription do
|
||||
# field(:id, :id)
|
||||
|
@ -29,8 +30,9 @@ defmodule Mobilizon.GraphQL.Schema.Users.PushSubscription do
|
|||
|
||||
middleware(Rajska.QueryAuthorization,
|
||||
permit: :user,
|
||||
scope: false,
|
||||
rule: :"write:user:setting:push"
|
||||
scope: User,
|
||||
rule: :"write:user:setting:push",
|
||||
args: %{}
|
||||
)
|
||||
|
||||
resolve(&PushSubscription.register_push_subscription/3)
|
||||
|
@ -41,8 +43,9 @@ defmodule Mobilizon.GraphQL.Schema.Users.PushSubscription do
|
|||
|
||||
middleware(Rajska.QueryAuthorization,
|
||||
permit: :user,
|
||||
scope: false,
|
||||
rule: :"write:user:setting:push"
|
||||
scope: User,
|
||||
rule: :"write:user:setting:push",
|
||||
args: %{}
|
||||
)
|
||||
|
||||
resolve(&PushSubscription.unregister_push_subscription/3)
|
||||
|
|
|
@ -19,6 +19,7 @@ defmodule Mobilizon.Activities do
|
|||
|
||||
@activity_types ["event", "post", "discussion", "resource", "group", "member", "comment"]
|
||||
@event_activity_subjects ["event_created", "event_updated", "event_deleted", "comment_posted"]
|
||||
@participant_activity_subjects ["event_new_participation"]
|
||||
@post_activity_subjects ["post_created", "post_updated", "post_deleted"]
|
||||
@discussion_activity_subjects [
|
||||
"discussion_created",
|
||||
|
@ -48,12 +49,23 @@ defmodule Mobilizon.Activities do
|
|||
@settings_activity_subjects ["group_created", "group_updated"]
|
||||
|
||||
@subjects @event_activity_subjects ++
|
||||
@participant_activity_subjects ++
|
||||
@post_activity_subjects ++
|
||||
@discussion_activity_subjects ++
|
||||
@resource_activity_subjects ++
|
||||
@member_activity_subjects ++ @settings_activity_subjects
|
||||
|
||||
@object_type ["event", "actor", "post", "discussion", "resource", "member", "group", "comment"]
|
||||
@object_type [
|
||||
"event",
|
||||
"participant",
|
||||
"actor",
|
||||
"post",
|
||||
"discussion",
|
||||
"resource",
|
||||
"member",
|
||||
"group",
|
||||
"comment"
|
||||
]
|
||||
|
||||
defenum(Type, @activity_types)
|
||||
defenum(Subject, @subjects)
|
||||
|
|
|
@ -4,7 +4,17 @@ defmodule Mobilizon.Service.Activity do
|
|||
"""
|
||||
|
||||
alias Mobilizon.Activities.Activity
|
||||
alias Mobilizon.Service.Activity.{Comment, Discussion, Event, Group, Member, Post, Resource}
|
||||
|
||||
alias Mobilizon.Service.Activity.{
|
||||
Comment,
|
||||
Discussion,
|
||||
Event,
|
||||
Group,
|
||||
Member,
|
||||
Participant,
|
||||
Post,
|
||||
Resource
|
||||
}
|
||||
|
||||
@callback insert_activity(entity :: struct(), options :: Keyword.t()) ::
|
||||
{:ok, Oban.Job.t()} | {:ok, any()} | {:error, Ecto.Changeset.t()}
|
||||
|
@ -45,4 +55,8 @@ defmodule Mobilizon.Service.Activity do
|
|||
defp do_get_object(:comment, comment_id) do
|
||||
Comment.get_object(comment_id)
|
||||
end
|
||||
|
||||
defp do_get_object(:participant, participant_id) do
|
||||
Participant.get_object(participant_id)
|
||||
end
|
||||
end
|
||||
|
|
48
lib/service/activity/participant.ex
Normal file
48
lib/service/activity/participant.ex
Normal file
|
@ -0,0 +1,48 @@
|
|||
defmodule Mobilizon.Service.Activity.Participant do
|
||||
@moduledoc """
|
||||
Insert an event activity
|
||||
"""
|
||||
alias Mobilizon.{Actors, Events}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.Participant
|
||||
alias Mobilizon.Service.Activity
|
||||
alias Mobilizon.Service.Workers.ActivityBuilder
|
||||
|
||||
@behaviour Activity
|
||||
|
||||
@impl Activity
|
||||
def insert_activity(event, options \\ [])
|
||||
|
||||
def insert_activity(
|
||||
%Participant{event_id: event_id, actor_id: actor_id, id: participant_id} =
|
||||
_participant,
|
||||
options
|
||||
) do
|
||||
actor = Actors.get_actor(actor_id)
|
||||
event = Events.get_event!(event_id)
|
||||
subject = Keyword.fetch!(options, :subject)
|
||||
|
||||
ActivityBuilder.enqueue(:build_activity, %{
|
||||
"type" => "event",
|
||||
"subject" => subject,
|
||||
"subject_params" => %{
|
||||
actor_name: Actor.display_name(actor),
|
||||
event_title: event.title,
|
||||
event_uuid: event.uuid
|
||||
},
|
||||
"group_id" => event.attributed_to_id,
|
||||
"author_id" => actor.id,
|
||||
"object_type" => "participant",
|
||||
"object_id" => participant_id,
|
||||
"inserted_at" => DateTime.utc_now()
|
||||
})
|
||||
end
|
||||
|
||||
@impl Activity
|
||||
def insert_activity(_, _), do: {:ok, nil}
|
||||
|
||||
@impl Activity
|
||||
def get_object(participant_id) do
|
||||
Events.get_participant(participant_id)
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
defmodule Mobilizon.Service.Activity.Renderer.Event do
|
||||
@moduledoc """
|
||||
Insert a comment activity
|
||||
Insert an event activity
|
||||
"""
|
||||
alias Mobilizon.Activities.Activity
|
||||
alias Mobilizon.Actors.Actor
|
||||
|
@ -67,6 +67,16 @@ defmodule Mobilizon.Service.Activity.Renderer.Event do
|
|||
url: event_url(activity)
|
||||
}
|
||||
end
|
||||
|
||||
:event_new_participation ->
|
||||
%{
|
||||
body:
|
||||
dgettext("activity", "%{profile} joined your event %{event}.", %{
|
||||
profile: profile(activity),
|
||||
event: title(activity)
|
||||
}),
|
||||
url: event_url(activity)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ defmodule Mobilizon.Service.DateTime do
|
|||
Module to represent a datetime in a given locale
|
||||
"""
|
||||
alias Cldr.DateTime.Relative
|
||||
alias Mobilizon.Cldr, as: MobilizonCldr
|
||||
import Mobilizon.Cldr, only: [locale_or_default: 1]
|
||||
|
||||
@typep to_string_format :: :short | :medium | :long | :full
|
||||
|
||||
|
@ -10,25 +12,25 @@ defmodule Mobilizon.Service.DateTime do
|
|||
|
||||
@spec datetime_to_string(DateTime.t(), String.t(), to_string_format()) :: String.t()
|
||||
def datetime_to_string(%DateTime{} = datetime, locale \\ "en", format \\ :medium) do
|
||||
Mobilizon.Cldr.DateTime.to_string!(datetime,
|
||||
MobilizonCldr.DateTime.to_string!(datetime,
|
||||
format: format,
|
||||
locale: Mobilizon.Cldr.locale_or_default(locale)
|
||||
locale: locale_or_default(locale)
|
||||
)
|
||||
end
|
||||
|
||||
@spec datetime_to_time_string(DateTime.t(), String.t(), to_string_format()) :: String.t()
|
||||
def datetime_to_time_string(%DateTime{} = datetime, locale \\ "en", format \\ :short) do
|
||||
Mobilizon.Cldr.Time.to_string!(datetime,
|
||||
MobilizonCldr.Time.to_string!(datetime,
|
||||
format: format,
|
||||
locale: Mobilizon.Cldr.locale_or_default(locale)
|
||||
locale: locale_or_default(locale)
|
||||
)
|
||||
end
|
||||
|
||||
@spec datetime_to_date_string(DateTime.t(), String.t(), to_string_format()) :: String.t()
|
||||
def datetime_to_date_string(%DateTime{} = datetime, locale \\ "en", format \\ :short) do
|
||||
Mobilizon.Cldr.Date.to_string!(datetime,
|
||||
MobilizonCldr.Date.to_string!(datetime,
|
||||
format: format,
|
||||
locale: Mobilizon.Cldr.locale_or_default(locale)
|
||||
locale: locale_or_default(locale)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -47,9 +49,9 @@ defmodule Mobilizon.Service.DateTime do
|
|||
|
||||
@spec datetime_relative(DateTime.t(), String.t()) :: String.t()
|
||||
def datetime_relative(%DateTime{} = datetime, locale \\ "en") do
|
||||
Relative.to_string!(datetime, Mobilizon.Cldr,
|
||||
Relative.to_string!(datetime, MobilizonCldr,
|
||||
relative_to: DateTime.utc_now(),
|
||||
locale: Mobilizon.Cldr.locale_or_default(locale)
|
||||
locale: locale_or_default(locale)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule Mobilizon.Service.Export.Participants.Common do
|
|||
alias Mobilizon.Events.Participant.Metadata
|
||||
alias Mobilizon.Storage.Repo
|
||||
import Mobilizon.Web.Gettext, only: [gettext: 1]
|
||||
import Mobilizon.Service.DateTime, only: [datetime_to_string: 2]
|
||||
|
||||
@spec save_upload(String.t(), String.t(), String.t(), String.t(), String.t()) ::
|
||||
{:ok, Export.t()} | {:error, atom() | Ecto.Changeset.t()}
|
||||
|
@ -58,7 +59,12 @@ defmodule Mobilizon.Service.Export.Participants.Common do
|
|||
|
||||
@spec columns :: list(String.t())
|
||||
def columns do
|
||||
[gettext("Participant name"), gettext("Participant status"), gettext("Participant message")]
|
||||
[
|
||||
gettext("Participant name"),
|
||||
gettext("Participant status"),
|
||||
gettext("Participant registration date"),
|
||||
gettext("Participant message")
|
||||
]
|
||||
end
|
||||
|
||||
# One hour
|
||||
|
@ -82,14 +88,26 @@ defmodule Mobilizon.Service.Export.Participants.Common do
|
|||
|
||||
@spec to_list({Participant.t(), Actor.t()}) :: list(String.t())
|
||||
def to_list(
|
||||
{%Participant{role: role, metadata: metadata},
|
||||
{%Participant{role: role, metadata: metadata, inserted_at: inserted_at},
|
||||
%Actor{domain: nil, preferred_username: "anonymous"}}
|
||||
) do
|
||||
[gettext("Anonymous participant"), translate_role(role), convert_metadata(metadata)]
|
||||
[
|
||||
gettext("Anonymous participant"),
|
||||
translate_role(role),
|
||||
datetime_to_string(inserted_at, Gettext.get_locale()),
|
||||
convert_metadata(metadata)
|
||||
]
|
||||
end
|
||||
|
||||
def to_list({%Participant{role: role, metadata: metadata}, %Actor{} = actor}) do
|
||||
[Actor.display_name_and_username(actor), translate_role(role), convert_metadata(metadata)]
|
||||
def to_list(
|
||||
{%Participant{role: role, metadata: metadata, inserted_at: inserted_at}, %Actor{} = actor}
|
||||
) do
|
||||
[
|
||||
Actor.display_name_and_username(actor),
|
||||
translate_role(role),
|
||||
datetime_to_string(inserted_at, Gettext.get_locale()),
|
||||
convert_metadata(metadata)
|
||||
]
|
||||
end
|
||||
|
||||
@spec convert_metadata(Metadata.t() | nil) :: String.t()
|
||||
|
|
|
@ -96,7 +96,7 @@ defmodule Mobilizon.Service.Notifier.Email do
|
|||
|
||||
defp can_send_activity?(activity, user, options) do
|
||||
Logger.warning(
|
||||
"Can't check if user #{inspect(user)} can be sent an activity (#{inspect(activity)}) (#{inspect(options)})"
|
||||
"Can't check if user #{inspect(user.email)} can be sent an activity (#{inspect(activity)}) (#{inspect(options)})"
|
||||
)
|
||||
|
||||
false
|
||||
|
|
|
@ -51,4 +51,13 @@
|
|||
})
|
||||
|> raw %>
|
||||
<% end %>
|
||||
<% :event_new_participation -> %>
|
||||
<%= dgettext("activity", "%{profile} joined your event %{event}.", %{
|
||||
profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>",
|
||||
event:
|
||||
"<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint,
|
||||
:event,
|
||||
@activity.subject_params["event_uuid"]) |> URI.decode()}\">#{escape_html(@activity.subject_params["event_title"])}</a>"
|
||||
})
|
||||
|> raw %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,31 +1,37 @@
|
|||
<%= case @activity.subject do %><% :event_created -> %><%= dgettext("activity", "The event %{event} was created by %{profile}.",
|
||||
%{
|
||||
profile: Mobilizon.Actors.Actor.display_name_and_username(@activity.author),
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% :event_updated -> %><%= dgettext("activity", "The event %{event} was updated by %{profile}.",
|
||||
%{
|
||||
profile: Mobilizon.Actors.Actor.display_name_and_username(@activity.author),
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% :event_deleted -> %><%= dgettext("activity", "The event %{event} was deleted by %{profile}.",
|
||||
%{
|
||||
profile: Mobilizon.Actors.Actor.display_name_and_username(@activity.author),
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<% :comment_posted -> %><%= if @activity.subject_params["comment_reply_to"] do %><%= dgettext("activity", "%{profile} replied to a comment on the event %{event}.",
|
||||
%{
|
||||
profile: Mobilizon.Actors.Actor.display_name_and_username(@activity.author),
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% else %><%= dgettext("activity", "%{profile} posted a comment on the event %{event}.",
|
||||
%{
|
||||
profile: Mobilizon.Actors.Actor.display_name_and_username(@activity.author),
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% end %><% end %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% end %><% :event_new_participation -> %><%= dgettext("activity", "%{profile} joined your event %{event}.",
|
||||
%{
|
||||
profile: display_name_and_username(@activity.author),
|
||||
event: @activity.subject_params["event_title"]
|
||||
}
|
||||
) %>
|
||||
<%= Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode() %><% end %>
|
|
@ -25,7 +25,6 @@ defmodule Mobilizon.Web.EmailView do
|
|||
defdelegate datetime_relative(datetime, locale \\ "en"), to: DateTimeRenderer
|
||||
defdelegate render_address(address), to: Address
|
||||
defdelegate is_same_day?(one, two), to: DateTimeRenderer
|
||||
defdelegate display_name_and_username(actor), to: Actor
|
||||
defdelegate display_name(actor), to: Actor
|
||||
defdelegate preferred_username_and_domain(actor), to: Actor
|
||||
|
||||
|
@ -38,7 +37,13 @@ defmodule Mobilizon.Web.EmailView do
|
|||
|
||||
def escaped_display_name_and_username(actor) do
|
||||
actor
|
||||
|> Actor.display_name_and_username()
|
||||
|> display_name_and_username()
|
||||
|> escape_html()
|
||||
end
|
||||
|
||||
def display_name_and_username(%Actor{preferred_username: "anonymous"}) do
|
||||
dgettext("activity", "An anonymous profile")
|
||||
end
|
||||
|
||||
def display_name_and_username(actor), do: Actor.display_name_and_username(actor)
|
||||
end
|
||||
|
|
149
test/graphql/resolvers/push_subscription_test.exs
Normal file
149
test/graphql/resolvers/push_subscription_test.exs
Normal file
|
@ -0,0 +1,149 @@
|
|||
defmodule Mobilizon.GraphQL.Resolvers.PushSubscriptionTest do
|
||||
use Mobilizon.Web.ConnCase
|
||||
|
||||
import Mobilizon.Factory
|
||||
|
||||
alias Mobilizon.GraphQL.AbsintheHelpers
|
||||
|
||||
describe "create a new push subscription" do
|
||||
@register_push_mutation """
|
||||
mutation RegisterPush($endpoint: String!, $auth: String!, $p256dh: String!) {
|
||||
registerPush(endpoint: $endpoint, auth: $auth, p256dh: $p256dh)
|
||||
}
|
||||
"""
|
||||
|
||||
test "without auth", %{conn: conn} do
|
||||
res =
|
||||
AbsintheHelpers.graphql_query(conn,
|
||||
query: @register_push_mutation,
|
||||
variables: %{endpoint: "https://yolo.com/gfjgfd", auth: "gjrigf", p256dh: "gbgof"}
|
||||
)
|
||||
|
||||
assert hd(res["errors"])["status_code"] == 401
|
||||
assert hd(res["errors"])["message"] == "You need to be logged in"
|
||||
end
|
||||
|
||||
test "succeeds", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @register_push_mutation,
|
||||
variables: %{endpoint: "https://yolo.com/gfjgfd", auth: "gjrigf", p256dh: "gbgof"}
|
||||
)
|
||||
|
||||
assert res["errors"] == nil
|
||||
assert res["data"]["registerPush"] == "OK"
|
||||
end
|
||||
|
||||
test "fails on duplicate", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @register_push_mutation,
|
||||
variables: %{
|
||||
endpoint: "https://yolo.com/duplicate",
|
||||
auth: "duplicate",
|
||||
p256dh: "duplicate"
|
||||
}
|
||||
)
|
||||
|
||||
assert res["errors"] == nil
|
||||
assert res["data"]["registerPush"] == "OK"
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @register_push_mutation,
|
||||
variables: %{
|
||||
endpoint: "https://yolo.com/duplicate",
|
||||
auth: "duplicate",
|
||||
p256dh: "duplicate"
|
||||
}
|
||||
)
|
||||
|
||||
assert hd(res["errors"])["message"] ==
|
||||
"The same push subscription has already been registered"
|
||||
|
||||
refute res["data"]["registerPush"] == "OK"
|
||||
end
|
||||
end
|
||||
|
||||
describe "unregister a push subscription" do
|
||||
@unregister_push_mutation """
|
||||
mutation UnRegisterPush($endpoint: String!) {
|
||||
unregisterPush(endpoint: $endpoint)
|
||||
}
|
||||
"""
|
||||
|
||||
test "without auth", %{conn: conn} do
|
||||
res =
|
||||
AbsintheHelpers.graphql_query(conn,
|
||||
query: @unregister_push_mutation,
|
||||
variables: %{endpoint: "https://yolo.com/gfjgfd"}
|
||||
)
|
||||
|
||||
assert hd(res["errors"])["status_code"] == 401
|
||||
assert hd(res["errors"])["message"] == "You need to be logged in"
|
||||
end
|
||||
|
||||
test "fails when not existing", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @unregister_push_mutation,
|
||||
variables: %{
|
||||
endpoint: "https://yolo.com/duplicate",
|
||||
auth: "duplicate",
|
||||
p256dh: "duplicate"
|
||||
}
|
||||
)
|
||||
|
||||
assert hd(res["errors"])["status_code"] == 404
|
||||
assert hd(res["errors"])["message"] == "Resource not found"
|
||||
refute res["data"]["registerPush"] == "OK"
|
||||
end
|
||||
|
||||
test "fails when wrong user", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
push_subscription = insert(:push_subscription)
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @unregister_push_mutation,
|
||||
variables: %{endpoint: push_subscription.endpoint}
|
||||
)
|
||||
|
||||
assert hd(res["errors"])["status_code"] == 403
|
||||
assert hd(res["errors"])["message"] == "You don't have permission to do this"
|
||||
refute res["data"]["registerPush"] == "OK"
|
||||
end
|
||||
|
||||
test "succeeds", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
push_subscription = insert(:push_subscription, user: user)
|
||||
|
||||
res =
|
||||
conn
|
||||
|> auth_conn(user)
|
||||
|> AbsintheHelpers.graphql_query(
|
||||
query: @unregister_push_mutation,
|
||||
variables: %{endpoint: push_subscription.endpoint}
|
||||
)
|
||||
|
||||
assert res["errors"] == nil
|
||||
assert res["data"]["unregisterPush"] == "OK"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,24 +5,28 @@ defmodule Mobilizon.Service.Export.Participants.CommonTest do
|
|||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Service.Export.Participants.Common
|
||||
import Mobilizon.Service.DateTime, only: [datetime_to_string: 1]
|
||||
|
||||
test "convert participants to list items" do
|
||||
participant = insert(:participant)
|
||||
actor = insert(:actor)
|
||||
name = Actor.display_name_and_username(actor)
|
||||
assert [^name, _, ""] = Common.to_list({participant, actor})
|
||||
date = datetime_to_string(participant.inserted_at)
|
||||
assert [^name, _, ^date, ""] = Common.to_list({participant, actor})
|
||||
end
|
||||
|
||||
test "convert participants with metadata to list items" do
|
||||
participant = insert(:participant, metadata: %{message: "a message"})
|
||||
actor = insert(:actor)
|
||||
name = Actor.display_name_and_username(actor)
|
||||
assert [^name, _, "a message"] = Common.to_list({participant, actor})
|
||||
date = datetime_to_string(participant.inserted_at)
|
||||
assert [^name, _, ^date, "a message"] = Common.to_list({participant, actor})
|
||||
end
|
||||
|
||||
test "convert anonymous participants to list items" do
|
||||
participant = insert(:participant)
|
||||
actor = insert(:actor, domain: nil, preferred_username: "anonymous")
|
||||
assert ["Anonymous participant", _, ""] = Common.to_list({participant, actor})
|
||||
date = datetime_to_string(participant.inserted_at)
|
||||
assert ["Anonymous participant", _, ^date, ""] = Common.to_list({participant, actor})
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue