Merge branch 'fix-security-issues' into 'master'
Fix security issues Closes #385 et #384 See merge request framasoft/mobilizon!599
This commit is contained in:
commit
507877ab18
@ -63,6 +63,7 @@ config :mobilizon, Mobilizon.Web.Upload,
|
||||
Mobilizon.Web.Upload.Filter.Dedupe,
|
||||
Mobilizon.Web.Upload.Filter.Optimize
|
||||
],
|
||||
allow_list_mime_types: ["image/gif", "image/jpeg", "image/png", "image/webp"],
|
||||
link_name: true,
|
||||
proxy_remote: false,
|
||||
proxy_opts: [
|
||||
|
@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div id="mobilizon">
|
||||
<NavBar />
|
||||
<div class="container" v-if="config && config.demoMode">
|
||||
<div v-if="config && config.demoMode">
|
||||
<b-message
|
||||
class="container"
|
||||
type="is-danger"
|
||||
:title="$t('Warning').toLocaleUpperCase()"
|
||||
closable
|
||||
@ -112,4 +113,14 @@ $mdi-font-path: "~@mdi/font/fonts";
|
||||
@import "~@mdi/font/scss/materialdesignicons";
|
||||
|
||||
@import "common";
|
||||
|
||||
#mobilizon {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -524,16 +524,23 @@ export default class EditorComponent extends Vue {
|
||||
*/
|
||||
async showImagePrompt(command: Function): Promise<void> {
|
||||
const image = await listenFileUpload();
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: UPLOAD_PICTURE,
|
||||
variables: {
|
||||
file: image,
|
||||
name: image.name,
|
||||
actorId: this.currentActor.id,
|
||||
},
|
||||
});
|
||||
if (data.uploadPicture && data.uploadPicture.url) {
|
||||
command({ src: data.uploadPicture.url });
|
||||
try {
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: UPLOAD_PICTURE,
|
||||
variables: {
|
||||
file: image,
|
||||
name: image.name,
|
||||
actorId: this.currentActor.id,
|
||||
},
|
||||
});
|
||||
if (data.uploadPicture && data.uploadPicture.url) {
|
||||
command({ src: data.uploadPicture.url });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||
this.$notifier.error(error.graphQLErrors[0].message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,8 @@ export default class Image extends Node {
|
||||
return false;
|
||||
}
|
||||
|
||||
const images = Array.from(realEvent.dataTransfer.files).filter((file: any) =>
|
||||
/image/i.test(file.type)
|
||||
const images = Array.from(realEvent.dataTransfer.files).filter(
|
||||
(file: any) => /image/i.test(file.type) && !/svg/i.test(file.type)
|
||||
);
|
||||
|
||||
if (images.length === 0) {
|
||||
@ -91,20 +91,25 @@ export default class Image extends Node {
|
||||
const editorElem = document.getElementById("tiptab-editor");
|
||||
const actorId = editorElem && editorElem.dataset.actorId;
|
||||
|
||||
images.forEach(async (image) => {
|
||||
const { data } = await client.mutate({
|
||||
mutation: UPLOAD_PICTURE,
|
||||
variables: {
|
||||
actorId,
|
||||
file: image,
|
||||
name: image.name,
|
||||
},
|
||||
try {
|
||||
images.forEach(async (image) => {
|
||||
const { data } = await client.mutate({
|
||||
mutation: UPLOAD_PICTURE,
|
||||
variables: {
|
||||
actorId,
|
||||
file: image,
|
||||
name: image.name,
|
||||
},
|
||||
});
|
||||
const node = schema.nodes.image.create({ src: data.uploadPicture.url });
|
||||
const transaction = view.state.tr.insert(coordinates.pos, node);
|
||||
view.dispatch(transaction);
|
||||
});
|
||||
const node = schema.nodes.image.create({ src: data.uploadPicture.url });
|
||||
const transaction = view.state.tr.insert(coordinates.pos, node);
|
||||
view.dispatch(transaction);
|
||||
});
|
||||
return true;
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
49
js/src/mixins/group.ts
Normal file
49
js/src/mixins/group.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { PERSON_MEMBERSHIPS, CURRENT_ACTOR_CLIENT } from "@/graphql/actor";
|
||||
import { FETCH_GROUP } from "@/graphql/group";
|
||||
import { Group, IActor, IGroup, IPerson, MemberRole } from "@/types/actor";
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
group: {
|
||||
query: FETCH_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
name: this.$route.params.preferredUsername,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.$route.params.preferredUsername;
|
||||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIPS,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
id: this.currentActor.id,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.currentActor || !this.currentActor.id;
|
||||
},
|
||||
},
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
})
|
||||
export default class GroupMixin extends Vue {
|
||||
group: IGroup = new Group();
|
||||
currentActor!: IActor;
|
||||
|
||||
person!: IPerson;
|
||||
|
||||
get isCurrentActorAGroupAdmin(): boolean {
|
||||
return (
|
||||
this.person &&
|
||||
this.person.memberships.elements.some(
|
||||
({ parent: { id }, role }) => id === this.group.id && role === MemberRole.ADMINISTRATOR
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -275,7 +275,7 @@ export class EventModel implements IEvent {
|
||||
|
||||
this.title = hash.title;
|
||||
this.slug = hash.slug;
|
||||
this.description = hash.description;
|
||||
this.description = hash.description || "";
|
||||
|
||||
this.beginsOn = new Date(hash.beginsOn);
|
||||
if (hash.endsOn) this.endsOn = new Date(hash.endsOn);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="container" v-if="isCurrentActorOrganizer">
|
||||
<h1 class="title" v-if="isUpdate === true">
|
||||
{{ $t("Update event {name}", { name: event.title }) }}
|
||||
</h1>
|
||||
@ -255,6 +255,7 @@
|
||||
aria-label="main navigation"
|
||||
class="navbar"
|
||||
:class="{ 'is-fixed-bottom': showFixedNavbar }"
|
||||
v-if="isCurrentActorOrganizer"
|
||||
>
|
||||
<div class="container">
|
||||
<div class="navbar-menu">
|
||||
@ -511,6 +512,8 @@ export default class EditEvent extends Vue {
|
||||
this.limitedPlaces = this.event.options.maximumAttendeeCapacity > 0;
|
||||
if (!(this.isUpdate || this.isDuplicate)) {
|
||||
this.initializeEvent();
|
||||
} else {
|
||||
this.event.description = this.event.description || "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,11 +536,6 @@ export default class EditEvent extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
@Watch("currentActor")
|
||||
setCurrentActor(): void {
|
||||
this.event.organizerActor = this.currentActor;
|
||||
}
|
||||
|
||||
@Watch("event")
|
||||
setInitialData(): void {
|
||||
if (this.isUpdate && this.unmodifiedEvent === undefined && this.event && this.event.uuid) {
|
||||
@ -588,6 +586,7 @@ export default class EditEvent extends Vue {
|
||||
} catch (err) {
|
||||
this.saving = false;
|
||||
console.error(err);
|
||||
this.handleError(err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -615,10 +614,18 @@ export default class EditEvent extends Vue {
|
||||
});
|
||||
} catch (err) {
|
||||
this.saving = false;
|
||||
console.error(err);
|
||||
this.handleError(err);
|
||||
}
|
||||
}
|
||||
|
||||
get isCurrentActorOrganizer(): boolean {
|
||||
return !(
|
||||
this.eventId &&
|
||||
this.event.organizerActor &&
|
||||
this.currentActor.id !== this.event.organizerActor.id
|
||||
) as boolean;
|
||||
}
|
||||
|
||||
get updateEventMessage(): string {
|
||||
if (this.unmodifiedEvent.draft && !this.event.draft)
|
||||
return this.$i18n.t("The event has been updated and published") as string;
|
||||
@ -627,6 +634,16 @@ export default class EditEvent extends Vue {
|
||||
: this.$i18n.t("The event has been updated")) as string;
|
||||
}
|
||||
|
||||
private handleError(err: any) {
|
||||
console.error(err);
|
||||
|
||||
if (err.graphQLErrors !== undefined) {
|
||||
err.graphQLErrors.forEach(({ message }: { message: string }) => {
|
||||
this.$notifier.error(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put in cache the updated or created event.
|
||||
* If the event is not a draft anymore, also put in cache the participation
|
||||
@ -709,6 +726,10 @@ export default class EditEvent extends Vue {
|
||||
* Build variables for Event GraphQL creation query
|
||||
*/
|
||||
private async buildVariables() {
|
||||
this.event.organizerActor =
|
||||
this.event.organizerActor && this.event.organizerActor.id
|
||||
? this.event.organizerActor
|
||||
: this.currentActor;
|
||||
let res = this.event.toEditJSON();
|
||||
if (this.event.organizerActor) {
|
||||
res = Object.assign(res, {
|
||||
|
@ -338,19 +338,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||
import { Component, Prop, Watch } from "vue-property-decorator";
|
||||
import EventCard from "@/components/Event/EventCard.vue";
|
||||
import { CURRENT_ACTOR_CLIENT, PERSON_MEMBERSHIPS } from "@/graphql/actor";
|
||||
import { FETCH_GROUP } from "@/graphql/group";
|
||||
import {
|
||||
IActor,
|
||||
IGroup,
|
||||
IPerson,
|
||||
usernameWithDomain,
|
||||
Group as GroupModel,
|
||||
MemberRole,
|
||||
IMember,
|
||||
} from "@/types/actor";
|
||||
import { IActor, usernameWithDomain, MemberRole, IMember } from "@/types/actor";
|
||||
import Subtitle from "@/components/Utils/Subtitle.vue";
|
||||
import CompactTodo from "@/components/Todo/CompactTodo.vue";
|
||||
import EventMinimalistCard from "@/components/Event/EventMinimalistCard.vue";
|
||||
@ -365,34 +355,14 @@ import { CONFIG } from "@/graphql/config";
|
||||
import { CREATE_REPORT } from "@/graphql/report";
|
||||
import { IReport } from "@/types/report.model";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import GroupMixin from "@/mixins/group";
|
||||
import { mixins } from "vue-class-component";
|
||||
import RouteName from "../../router/name";
|
||||
import GroupSection from "../../components/Group/GroupSection.vue";
|
||||
import ReportModal from "../../components/Report/ReportModal.vue";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
group: {
|
||||
query: FETCH_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
name: this.preferredUsername,
|
||||
};
|
||||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIPS,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
id: this.currentActor.id,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.currentActor || !this.currentActor.id;
|
||||
},
|
||||
},
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
config: CONFIG,
|
||||
},
|
||||
components: {
|
||||
@ -425,15 +395,9 @@ import ReportModal from "../../components/Report/ReportModal.vue";
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Group extends Vue {
|
||||
export default class Group extends mixins(GroupMixin) {
|
||||
@Prop({ type: String, required: true }) preferredUsername!: string;
|
||||
|
||||
currentActor!: IActor;
|
||||
|
||||
person!: IPerson;
|
||||
|
||||
group: IGroup = new GroupModel();
|
||||
|
||||
config!: IConfig;
|
||||
|
||||
loading = true;
|
||||
@ -550,15 +514,6 @@ export default class Group extends Vue {
|
||||
);
|
||||
}
|
||||
|
||||
get isCurrentActorAGroupAdmin(): boolean {
|
||||
return (
|
||||
this.person &&
|
||||
this.person.memberships.elements.some(
|
||||
({ parent: { id }, role }) => id === this.group.id && role === MemberRole.ADMINISTRATOR
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* New members, if on a different server,
|
||||
* can take a while to refresh the group and fetch all private data
|
||||
|
@ -31,7 +31,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section class="container section" v-if="group">
|
||||
<section class="container section" v-if="group && isCurrentActorAGroupAdmin">
|
||||
<form @submit.prevent="inviteMember">
|
||||
<b-field :label="$t('Invite a new member')" custom-class="add-relay" horizontal>
|
||||
<b-field
|
||||
@ -171,42 +171,23 @@
|
||||
</template>
|
||||
</b-table>
|
||||
</section>
|
||||
<b-message v-else-if="group">
|
||||
{{ $t("You are not an administrator for this group.") }}
|
||||
</b-message>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
import { CURRENT_ACTOR_CLIENT } from "@/graphql/actor";
|
||||
import { Component, Watch } from "vue-property-decorator";
|
||||
import GroupMixin from "@/mixins/group";
|
||||
import { mixins } from "vue-class-component";
|
||||
import RouteName from "../../router/name";
|
||||
import { INVITE_MEMBER, GROUP_MEMBERS, REMOVE_MEMBER, UPDATE_MEMBER } from "../../graphql/member";
|
||||
import { IGroup, IPerson, usernameWithDomain } from "../../types/actor";
|
||||
import { IGroup, usernameWithDomain } from "../../types/actor";
|
||||
import { IMember, MemberRole } from "../../types/actor/group.model";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
group: {
|
||||
query: GROUP_MEMBERS,
|
||||
fetchPolicy: "network-only",
|
||||
variables() {
|
||||
return {
|
||||
name: this.$route.params.preferredUsername,
|
||||
page: 1,
|
||||
limit: this.MEMBERS_PER_PAGE,
|
||||
roles: this.roles,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.$route.params.preferredUsername;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
export default class GroupMembers extends Vue {
|
||||
group!: IGroup;
|
||||
|
||||
currentActor!: IPerson;
|
||||
|
||||
@Component
|
||||
export default class GroupMembers extends mixins(GroupMixin) {
|
||||
loading = true;
|
||||
|
||||
newMemberUsername = "";
|
||||
|
@ -31,7 +31,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section class="container section">
|
||||
<section class="container section" v-if="isCurrentActorAGroupAdmin">
|
||||
<form @submit.prevent="updateGroup">
|
||||
<b-field :label="$t('Group name')">
|
||||
<b-input v-model="group.name" />
|
||||
@ -114,44 +114,32 @@
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<b-message>
|
||||
{{ $t("You are not an administrator for this group.") }}
|
||||
</b-message>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { Component } from "vue-property-decorator";
|
||||
import FullAddressAutoComplete from "@/components/Event/FullAddressAutoComplete.vue";
|
||||
import { Route } from "vue-router";
|
||||
import PictureUpload from "@/components/PictureUpload.vue";
|
||||
import { mixins } from "vue-class-component";
|
||||
import GroupMixin from "@/mixins/group";
|
||||
import RouteName from "../../router/name";
|
||||
import { FETCH_GROUP, UPDATE_GROUP, DELETE_GROUP } from "../../graphql/group";
|
||||
import { UPDATE_GROUP, DELETE_GROUP } from "../../graphql/group";
|
||||
import { IGroup, usernameWithDomain } from "../../types/actor";
|
||||
import { Address, IAddress } from "../../types/address.model";
|
||||
import { Group } from "../../types/actor/group.model";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
group: {
|
||||
query: FETCH_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
name: this.$route.params.preferredUsername,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.$route.params.preferredUsername;
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
FullAddressAutoComplete,
|
||||
PictureUpload,
|
||||
editor: () => import("../../components/Editor.vue"),
|
||||
},
|
||||
})
|
||||
export default class GroupSettings extends Vue {
|
||||
group: IGroup = new Group();
|
||||
|
||||
export default class GroupSettings extends mixins(GroupMixin) {
|
||||
loading = true;
|
||||
|
||||
RouteName = RouteName;
|
||||
|
@ -23,8 +23,9 @@
|
||||
</aside>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { IGroup } from "@/types/actor";
|
||||
import { Component } from "vue-property-decorator";
|
||||
import { mixins } from "vue-class-component";
|
||||
import GroupMixin from "@/mixins/group";
|
||||
import RouteName from "../../router/name";
|
||||
import SettingMenuSection from "../../components/Settings/SettingMenuSection.vue";
|
||||
import SettingMenuItem from "../../components/Settings/SettingMenuItem.vue";
|
||||
@ -32,10 +33,8 @@ import SettingMenuItem from "../../components/Settings/SettingMenuItem.vue";
|
||||
@Component({
|
||||
components: { SettingMenuSection, SettingMenuItem },
|
||||
})
|
||||
export default class Settings extends Vue {
|
||||
export default class Settings extends mixins(GroupMixin) {
|
||||
RouteName = RouteName;
|
||||
|
||||
group!: IGroup[];
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -219,14 +219,16 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
def update_event(
|
||||
_parent,
|
||||
%{event_id: event_id} = args,
|
||||
%{context: %{current_user: user}} = _resolution
|
||||
%{context: %{current_user: %User{} = user}} = _resolution
|
||||
) do
|
||||
# See https://github.com/absinthe-graphql/absinthe/issues/490
|
||||
with args <- Map.put(args, :options, args[:options] || %{}),
|
||||
{:ok, %Event{} = event} <- Events.get_event_with_preload(event_id),
|
||||
organizer_actor_id <- args |> Map.get(:organizer_actor_id, event.organizer_actor_id),
|
||||
{:is_owned, %Actor{} = organizer_actor} <-
|
||||
User.owns_actor(user, organizer_actor_id),
|
||||
{:old_actor, {:is_owned, %Actor{}}} <-
|
||||
{:old_actor, User.owns_actor(user, event.organizer_actor_id)},
|
||||
new_organizer_actor_id <- args |> Map.get(:organizer_actor_id, event.organizer_actor_id),
|
||||
{:new_actor, {:is_owned, %Actor{} = organizer_actor}} <-
|
||||
{:new_actor, User.owns_actor(user, new_organizer_actor_id)},
|
||||
args <- Map.put(args, :organizer_actor, organizer_actor),
|
||||
{:ok, %Activity{data: %{"object" => %{"type" => "Event"}}}, %Event{} = event} <-
|
||||
API.Events.update_event(args, event) do
|
||||
@ -235,8 +237,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
{:error, :event_not_found} ->
|
||||
{:error, dgettext("errors", "Event not found")}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, dgettext("errors", "User doesn't own profile")}
|
||||
{:old_actor, _} ->
|
||||
{:error, dgettext("errors", "You can't edit this event.")}
|
||||
|
||||
{:new_actor, _} ->
|
||||
{:error, dgettext("errors", "You can't attribute this event to this profile.")}
|
||||
|
||||
{:error, _, %Ecto.Changeset{} = error, _} ->
|
||||
{:error, error}
|
||||
|
@ -145,11 +145,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create a new group. The creator is automatically added as admin
|
||||
Update a group. The creator is automatically added as admin
|
||||
"""
|
||||
def update_group(
|
||||
_parent,
|
||||
args,
|
||||
%{id: group_id} = args,
|
||||
%{
|
||||
context: %{
|
||||
current_user: %User{} = user
|
||||
@ -157,6 +157,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||
}
|
||||
) do
|
||||
with %Actor{} = updater_actor <- Users.get_actor_for_user(user),
|
||||
{:administrator, true} <-
|
||||
{:administrator, Actors.is_administrator?(updater_actor.id, group_id)},
|
||||
args <- Map.put(args, :updater_actor, updater_actor),
|
||||
args <- save_attached_pictures(args),
|
||||
{:ok, _activity, %Actor{type: :Group} = group} <-
|
||||
@ -166,8 +168,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||
{:error, err} when is_binary(err) ->
|
||||
{:error, err}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, dgettext("errors", "Creator profile is not owned by the current user")}
|
||||
{:administrator, false} ->
|
||||
{:error, dgettext("errors", "Profile is not administrator for the group")}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,6 +74,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
|
||||
{:is_owned, nil} ->
|
||||
{:error, dgettext("errors", "Profile is not owned by authenticated user")}
|
||||
|
||||
{:error, :mime_type_not_allowed} ->
|
||||
{:error, dgettext("errors", "File doesn't have an allowed MIME type.")}
|
||||
|
||||
error ->
|
||||
{:error, error}
|
||||
end
|
||||
|
@ -704,6 +704,22 @@ defmodule Mobilizon.Actors do
|
||||
)
|
||||
end
|
||||
|
||||
@spec is_moderator?(integer | String.t(), integer | String.t()) :: boolean()
|
||||
def is_moderator?(actor_id, parent_id) do
|
||||
match?(
|
||||
{:ok, %Member{}},
|
||||
get_member(actor_id, parent_id, @moderator_roles)
|
||||
)
|
||||
end
|
||||
|
||||
@spec is_administrator?(integer | String.t(), integer | String.t()) :: boolean()
|
||||
def is_administrator?(actor_id, parent_id) do
|
||||
match?(
|
||||
{:ok, %Member{}},
|
||||
get_member(actor_id, parent_id, @administrator_roles)
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single member of an actor (for example a group).
|
||||
"""
|
||||
|
@ -38,8 +38,8 @@
|
||||
<body class="error">
|
||||
<main role="main" class="dialog">
|
||||
<div class="error_illustration">
|
||||
<img src="/static/img/mobilizon_logo.png" />
|
||||
<!-- <img src="/static/img/error.png" alt="" width="500" /> -->
|
||||
<img src="/img/mobilizon_logo.png" />
|
||||
<!-- <img src="/img/error.png" alt="" width="500" /> -->
|
||||
</div>
|
||||
<div class="error__message">
|
||||
<h1><%= gettext "We're sorry, but something went wrong on our end." %></h1>
|
||||
|
@ -126,6 +126,12 @@ defmodule Mobilizon.Web.Upload do
|
||||
uploader: Keyword.get(opts, :uploader, Config.get([__MODULE__, :uploader])),
|
||||
filters: Keyword.get(opts, :filters, Config.get([__MODULE__, :filters])),
|
||||
description: Keyword.get(opts, :description),
|
||||
allow_list_mime_types:
|
||||
Keyword.get(
|
||||
opts,
|
||||
:allow_list_mime_types,
|
||||
Config.get([__MODULE__, :allow_list_mime_types])
|
||||
),
|
||||
base_url:
|
||||
Keyword.get(
|
||||
opts,
|
||||
@ -137,7 +143,8 @@ defmodule Mobilizon.Web.Upload do
|
||||
|
||||
defp prepare_upload(%Plug.Upload{} = file, opts) do
|
||||
with {:ok, size} <- check_file_size(file.path, opts.size_limit),
|
||||
{:ok, content_type, name} <- MIME.file_mime_type(file.path, file.filename) do
|
||||
{:ok, content_type, name} <- MIME.file_mime_type(file.path, file.filename),
|
||||
:ok <- check_allowed_mime_type(content_type, opts.allow_list_mime_types) do
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
id: UUID.generate(),
|
||||
@ -152,7 +159,8 @@ defmodule Mobilizon.Web.Upload do
|
||||
defp prepare_upload(%{body: body, name: name} = _file, opts) do
|
||||
with :ok <- check_binary_size(body, opts.size_limit),
|
||||
tmp_path <- tempfile_for_image(body),
|
||||
{:ok, content_type, name} <- MIME.file_mime_type(tmp_path, name) do
|
||||
{:ok, content_type, name} <- MIME.file_mime_type(tmp_path, name),
|
||||
:ok <- check_allowed_mime_type(content_type, opts.allow_list_mime_types) do
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
id: UUID.generate(),
|
||||
@ -207,4 +215,11 @@ defmodule Mobilizon.Web.Upload do
|
||||
end
|
||||
|
||||
defp url_from_spec(_upload, _base_url, {:url, url}), do: url
|
||||
|
||||
@spec check_allowed_mime_type(String.t(), List.t()) :: :ok | {:error, :atom}
|
||||
defp check_allowed_mime_type(content_type, allow_list_mime_types) do
|
||||
if Enum.any?(allow_list_mime_types, &(&1 == content_type)),
|
||||
do: :ok,
|
||||
else: {:error, :mime_type_not_allowed}
|
||||
end
|
||||
end
|
||||
|
@ -124,17 +124,17 @@ msgid "Cannot refresh the token"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:139 lib/graphql/resolvers/group.ex:170
|
||||
#: lib/graphql/resolvers/group.ex:139
|
||||
msgid "Creator profile is not owned by the current user"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:201
|
||||
#: lib/graphql/resolvers/group.ex:203
|
||||
msgid "Current profile is not a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:205
|
||||
#: lib/graphql/resolvers/group.ex:207
|
||||
msgid "Current profile is not an administrator of the selected group"
|
||||
msgstr ""
|
||||
|
||||
@ -144,8 +144,8 @@ msgid "Error while saving user settings"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:198 lib/graphql/resolvers/group.ex:246
|
||||
#: lib/graphql/resolvers/group.ex:281 lib/graphql/resolvers/member.ex:80
|
||||
#: lib/graphql/resolvers/group.ex:200 lib/graphql/resolvers/group.ex:248
|
||||
#: lib/graphql/resolvers/group.ex:283 lib/graphql/resolvers/member.ex:80
|
||||
msgid "Group not found"
|
||||
msgstr ""
|
||||
|
||||
@ -165,7 +165,7 @@ msgid "Impossible to authenticate, either your email or password are invalid."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:278
|
||||
#: lib/graphql/resolvers/group.ex:280
|
||||
msgid "Member not found"
|
||||
msgstr ""
|
||||
|
||||
@ -188,7 +188,7 @@ msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/comment.ex:50 lib/graphql/resolvers/comment.ex:112
|
||||
#: lib/graphql/resolvers/event.ex:281 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:243
|
||||
#: lib/graphql/resolvers/event.ex:286 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:245
|
||||
#: lib/graphql/resolvers/member.ex:77 lib/graphql/resolvers/participant.ex:29
|
||||
#: lib/graphql/resolvers/participant.ex:163 lib/graphql/resolvers/participant.ex:192 lib/graphql/resolvers/person.ex:157
|
||||
#: lib/graphql/resolvers/person.ex:191 lib/graphql/resolvers/person.ex:256 lib/graphql/resolvers/person.ex:288
|
||||
@ -259,17 +259,17 @@ msgid "User requested is not logged-in"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:252
|
||||
#: lib/graphql/resolvers/group.ex:254
|
||||
msgid "You are already a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:285
|
||||
#: lib/graphql/resolvers/group.ex:287
|
||||
msgid "You can't leave this group because you are the only administrator"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:249
|
||||
#: lib/graphql/resolvers/group.ex:251
|
||||
msgid "You cannot join this group"
|
||||
msgstr ""
|
||||
|
||||
@ -289,7 +289,7 @@ msgid "You need to be logged-in to change your password"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:210
|
||||
#: lib/graphql/resolvers/group.ex:212
|
||||
msgid "You need to be logged-in to delete a group"
|
||||
msgstr ""
|
||||
|
||||
@ -299,17 +299,17 @@ msgid "You need to be logged-in to delete your account"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:257
|
||||
#: lib/graphql/resolvers/group.ex:259
|
||||
msgid "You need to be logged-in to join a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:290
|
||||
#: lib/graphql/resolvers/group.ex:292
|
||||
msgid "You need to be logged-in to leave a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:175
|
||||
#: lib/graphql/resolvers/group.ex:177
|
||||
msgid "You need to be logged-in to update a group"
|
||||
msgstr ""
|
||||
|
||||
@ -414,8 +414,8 @@ msgid "Event id not found"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:236
|
||||
#: lib/graphql/resolvers/event.ex:278
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:238
|
||||
#: lib/graphql/resolvers/event.ex:283
|
||||
msgid "Event not found"
|
||||
msgstr ""
|
||||
|
||||
@ -567,11 +567,6 @@ msgstr ""
|
||||
msgid "Token is not a valid UUID"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:239
|
||||
msgid "User doesn't own profile"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:87 lib/graphql/resolvers/person.ex:323
|
||||
msgid "User not found"
|
||||
@ -644,7 +639,7 @@ msgid "You cannot delete this comment"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:274
|
||||
#: lib/graphql/resolvers/event.ex:279
|
||||
msgid "You cannot delete this event"
|
||||
msgstr ""
|
||||
|
||||
@ -724,7 +719,7 @@ msgid "You need to be logged-in to create resources"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:286
|
||||
#: lib/graphql/resolvers/event.ex:291
|
||||
msgid "You need to be logged-in to delete an event"
|
||||
msgstr ""
|
||||
|
||||
@ -749,7 +744,7 @@ msgid "You need to be logged-in to leave an event"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:247
|
||||
#: lib/graphql/resolvers/event.ex:252
|
||||
msgid "You need to be logged-in to update an event"
|
||||
msgstr ""
|
||||
|
||||
@ -769,7 +764,7 @@ msgid "You need to be logged-in to view a resource preview"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:83
|
||||
#: lib/graphql/resolvers/picture.ex:86
|
||||
msgid "You need to login to upload a picture"
|
||||
msgstr ""
|
||||
|
||||
@ -862,3 +857,23 @@ msgstr ""
|
||||
#: lib/graphql/resolvers/member.ex:129
|
||||
msgid "You can't reject this invitation with this profile."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:78
|
||||
msgid "File doesn't have an allowed MIME type."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:172
|
||||
msgid "Profile is not administrator for the group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:241
|
||||
msgid "You can't edit this event."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format, fuzzy
|
||||
#: lib/graphql/resolvers/event.ex:244
|
||||
msgid "You can't attribute this event to this profile."
|
||||
msgstr ""
|
||||
|
@ -98,17 +98,17 @@ msgid "Cannot refresh the token"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:139 lib/graphql/resolvers/group.ex:170
|
||||
#: lib/graphql/resolvers/group.ex:139
|
||||
msgid "Creator profile is not owned by the current user"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:201
|
||||
#: lib/graphql/resolvers/group.ex:203
|
||||
msgid "Current profile is not a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:205
|
||||
#: lib/graphql/resolvers/group.ex:207
|
||||
msgid "Current profile is not an administrator of the selected group"
|
||||
msgstr ""
|
||||
|
||||
@ -118,8 +118,8 @@ msgid "Error while saving user settings"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:198 lib/graphql/resolvers/group.ex:246
|
||||
#: lib/graphql/resolvers/group.ex:281 lib/graphql/resolvers/member.ex:80
|
||||
#: lib/graphql/resolvers/group.ex:200 lib/graphql/resolvers/group.ex:248
|
||||
#: lib/graphql/resolvers/group.ex:283 lib/graphql/resolvers/member.ex:80
|
||||
msgid "Group not found"
|
||||
msgstr ""
|
||||
|
||||
@ -139,7 +139,7 @@ msgid "Impossible to authenticate, either your email or password are invalid."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:278
|
||||
#: lib/graphql/resolvers/group.ex:280
|
||||
msgid "Member not found"
|
||||
msgstr ""
|
||||
|
||||
@ -162,7 +162,7 @@ msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/comment.ex:50 lib/graphql/resolvers/comment.ex:112
|
||||
#: lib/graphql/resolvers/event.ex:281 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:243
|
||||
#: lib/graphql/resolvers/event.ex:286 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:245
|
||||
#: lib/graphql/resolvers/member.ex:77 lib/graphql/resolvers/participant.ex:29
|
||||
#: lib/graphql/resolvers/participant.ex:163 lib/graphql/resolvers/participant.ex:192 lib/graphql/resolvers/person.ex:157
|
||||
#: lib/graphql/resolvers/person.ex:191 lib/graphql/resolvers/person.ex:256 lib/graphql/resolvers/person.ex:288
|
||||
@ -233,17 +233,17 @@ msgid "User requested is not logged-in"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:252
|
||||
#: lib/graphql/resolvers/group.ex:254
|
||||
msgid "You are already a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:285
|
||||
#: lib/graphql/resolvers/group.ex:287
|
||||
msgid "You can't leave this group because you are the only administrator"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:249
|
||||
#: lib/graphql/resolvers/group.ex:251
|
||||
msgid "You cannot join this group"
|
||||
msgstr ""
|
||||
|
||||
@ -263,7 +263,7 @@ msgid "You need to be logged-in to change your password"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:210
|
||||
#: lib/graphql/resolvers/group.ex:212
|
||||
msgid "You need to be logged-in to delete a group"
|
||||
msgstr ""
|
||||
|
||||
@ -273,17 +273,17 @@ msgid "You need to be logged-in to delete your account"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:257
|
||||
#: lib/graphql/resolvers/group.ex:259
|
||||
msgid "You need to be logged-in to join a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:290
|
||||
#: lib/graphql/resolvers/group.ex:292
|
||||
msgid "You need to be logged-in to leave a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:175
|
||||
#: lib/graphql/resolvers/group.ex:177
|
||||
msgid "You need to be logged-in to update a group"
|
||||
msgstr ""
|
||||
|
||||
@ -388,8 +388,8 @@ msgid "Event id not found"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:236
|
||||
#: lib/graphql/resolvers/event.ex:278
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:238
|
||||
#: lib/graphql/resolvers/event.ex:283
|
||||
msgid "Event not found"
|
||||
msgstr ""
|
||||
|
||||
@ -541,11 +541,6 @@ msgstr ""
|
||||
msgid "Token is not a valid UUID"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:239
|
||||
msgid "User doesn't own profile"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:87 lib/graphql/resolvers/person.ex:323
|
||||
msgid "User not found"
|
||||
@ -618,7 +613,7 @@ msgid "You cannot delete this comment"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:274
|
||||
#: lib/graphql/resolvers/event.ex:279
|
||||
msgid "You cannot delete this event"
|
||||
msgstr ""
|
||||
|
||||
@ -698,7 +693,7 @@ msgid "You need to be logged-in to create resources"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:286
|
||||
#: lib/graphql/resolvers/event.ex:291
|
||||
msgid "You need to be logged-in to delete an event"
|
||||
msgstr ""
|
||||
|
||||
@ -723,7 +718,7 @@ msgid "You need to be logged-in to leave an event"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:247
|
||||
#: lib/graphql/resolvers/event.ex:252
|
||||
msgid "You need to be logged-in to update an event"
|
||||
msgstr ""
|
||||
|
||||
@ -743,7 +738,7 @@ msgid "You need to be logged-in to view a resource preview"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:83
|
||||
#: lib/graphql/resolvers/picture.ex:86
|
||||
msgid "You need to login to upload a picture"
|
||||
msgstr ""
|
||||
|
||||
@ -836,3 +831,23 @@ msgstr ""
|
||||
#: lib/graphql/resolvers/member.ex:129
|
||||
msgid "You can't reject this invitation with this profile."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:78
|
||||
msgid "File doesn't have an allowed MIME type."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:172
|
||||
msgid "Profile is not administrator for the group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:241
|
||||
msgid "You can't edit this event."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format, fuzzy
|
||||
#: lib/graphql/resolvers/event.ex:244
|
||||
msgid "You can't attribute this event to this profile."
|
||||
msgstr ""
|
||||
|
@ -92,17 +92,17 @@ msgid "Cannot refresh the token"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:139 lib/graphql/resolvers/group.ex:170
|
||||
#: lib/graphql/resolvers/group.ex:139
|
||||
msgid "Creator profile is not owned by the current user"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:201
|
||||
#: lib/graphql/resolvers/group.ex:203
|
||||
msgid "Current profile is not a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:205
|
||||
#: lib/graphql/resolvers/group.ex:207
|
||||
msgid "Current profile is not an administrator of the selected group"
|
||||
msgstr ""
|
||||
|
||||
@ -112,8 +112,8 @@ msgid "Error while saving user settings"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:198 lib/graphql/resolvers/group.ex:246
|
||||
#: lib/graphql/resolvers/group.ex:281 lib/graphql/resolvers/member.ex:80
|
||||
#: lib/graphql/resolvers/group.ex:200 lib/graphql/resolvers/group.ex:248
|
||||
#: lib/graphql/resolvers/group.ex:283 lib/graphql/resolvers/member.ex:80
|
||||
msgid "Group not found"
|
||||
msgstr ""
|
||||
|
||||
@ -133,7 +133,7 @@ msgid "Impossible to authenticate, either your email or password are invalid."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:278
|
||||
#: lib/graphql/resolvers/group.ex:280
|
||||
msgid "Member not found"
|
||||
msgstr ""
|
||||
|
||||
@ -156,7 +156,7 @@ msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/comment.ex:50 lib/graphql/resolvers/comment.ex:112
|
||||
#: lib/graphql/resolvers/event.ex:281 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:243
|
||||
#: lib/graphql/resolvers/event.ex:286 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:245
|
||||
#: lib/graphql/resolvers/member.ex:77 lib/graphql/resolvers/participant.ex:29
|
||||
#: lib/graphql/resolvers/participant.ex:163 lib/graphql/resolvers/participant.ex:192 lib/graphql/resolvers/person.ex:157
|
||||
#: lib/graphql/resolvers/person.ex:191 lib/graphql/resolvers/person.ex:256 lib/graphql/resolvers/person.ex:288
|
||||
@ -227,17 +227,17 @@ msgid "User requested is not logged-in"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:252
|
||||
#: lib/graphql/resolvers/group.ex:254
|
||||
msgid "You are already a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:285
|
||||
#: lib/graphql/resolvers/group.ex:287
|
||||
msgid "You can't leave this group because you are the only administrator"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:249
|
||||
#: lib/graphql/resolvers/group.ex:251
|
||||
msgid "You cannot join this group"
|
||||
msgstr ""
|
||||
|
||||
@ -257,7 +257,7 @@ msgid "You need to be logged-in to change your password"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:210
|
||||
#: lib/graphql/resolvers/group.ex:212
|
||||
msgid "You need to be logged-in to delete a group"
|
||||
msgstr ""
|
||||
|
||||
@ -267,17 +267,17 @@ msgid "You need to be logged-in to delete your account"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:257
|
||||
#: lib/graphql/resolvers/group.ex:259
|
||||
msgid "You need to be logged-in to join a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:290
|
||||
#: lib/graphql/resolvers/group.ex:292
|
||||
msgid "You need to be logged-in to leave a group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:175
|
||||
#: lib/graphql/resolvers/group.ex:177
|
||||
msgid "You need to be logged-in to update a group"
|
||||
msgstr ""
|
||||
|
||||
@ -382,8 +382,8 @@ msgid "Event id not found"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:236
|
||||
#: lib/graphql/resolvers/event.ex:278
|
||||
#: lib/graphql/error.ex:89 lib/graphql/resolvers/event.ex:238
|
||||
#: lib/graphql/resolvers/event.ex:283
|
||||
msgid "Event not found"
|
||||
msgstr ""
|
||||
|
||||
@ -535,11 +535,6 @@ msgstr ""
|
||||
msgid "Token is not a valid UUID"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:239
|
||||
msgid "User doesn't own profile"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/error.ex:87 lib/graphql/resolvers/person.ex:323
|
||||
msgid "User not found"
|
||||
@ -612,7 +607,7 @@ msgid "You cannot delete this comment"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:274
|
||||
#: lib/graphql/resolvers/event.ex:279
|
||||
msgid "You cannot delete this event"
|
||||
msgstr ""
|
||||
|
||||
@ -692,7 +687,7 @@ msgid "You need to be logged-in to create resources"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:286
|
||||
#: lib/graphql/resolvers/event.ex:291
|
||||
msgid "You need to be logged-in to delete an event"
|
||||
msgstr ""
|
||||
|
||||
@ -717,7 +712,7 @@ msgid "You need to be logged-in to leave an event"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:247
|
||||
#: lib/graphql/resolvers/event.ex:252
|
||||
msgid "You need to be logged-in to update an event"
|
||||
msgstr ""
|
||||
|
||||
@ -737,7 +732,7 @@ msgid "You need to be logged-in to view a resource preview"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:83
|
||||
#: lib/graphql/resolvers/picture.ex:86
|
||||
msgid "You need to login to upload a picture"
|
||||
msgstr ""
|
||||
|
||||
@ -830,3 +825,23 @@ msgstr ""
|
||||
#: lib/graphql/resolvers/member.ex:129
|
||||
msgid "You can't reject this invitation with this profile."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/picture.ex:78
|
||||
msgid "File doesn't have an allowed MIME type."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:172
|
||||
msgid "Profile is not administrator for the group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/event.ex:241
|
||||
msgid "You can't edit this event."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format, fuzzy
|
||||
#: lib/graphql/resolvers/event.ex:244
|
||||
msgid "You can't attribute this event to this profile."
|
||||
msgstr ""
|
||||
|
@ -98,17 +98,17 @@ msgid "Cannot refresh the token"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:139 lib/graphql/resolvers/group.ex:170
|
||||
#: lib/graphql/resolvers/group.ex:139
|
||||
msgid "Creator profile is not owned by the current user"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:201
|
||||
#: lib/graphql/resolvers/group.ex:203
|
||||
msgid "Current profile is not a member of this group"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:205
|
||||
#: lib/graphql/resolvers/group.ex:207
|
||||
msgid "Current profile is not an administrator of the selected group"
|
||||
msgstr ""
|
||||
|
||||
@ -118,8 +118,8 @@ msgid "Error while saving user settings"
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:198 lib/graphql/resolvers/group.ex:246
|
||||
#: lib/graphql/resolvers/group.ex:281 lib/graphql/resolvers/member.ex:80
|
||||
#: lib/graphql/resolvers/group.ex:200 lib/graphql/resolvers/group.ex:248
|
||||
#: lib/graphql/resolvers/group.ex:283 lib/graphql/resolvers/member.ex:80
|
||||
msgid "Group not found"
|
||||
msgstr ""
|
||||
|
||||
@ -139,7 +139,7 @@ msgid "Impossible to authenticate, either your email or password are invalid."
|
||||
msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/group.ex:278
|
||||
#: lib/graphql/resolvers/group.ex:280
|
||||
msgid "Member not found"
|
||||
msgstr ""
|
||||
|
||||
@ -162,7 +162,7 @@ msgstr ""
|
||||
|
||||
#, elixir-format
|
||||
#: lib/graphql/resolvers/comment.ex:50 lib/graphql/resolvers/comment.ex:112
|
||||
#: lib/graphql/resolvers/event.ex:281 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:243
|
||||
#: lib/graphql/resolvers/event.ex:286 lib/graphql/resolvers/feed_token.ex:28 lib/graphql/resolvers/group.ex:245
|
||||
#: lib/graphql/resolvers/member.ex:77 lib/graphql/resolvers/participant.ex:29
|
||||
#: lib/graphql/resolvers/participant.ex:163 lib/graphql/resolvers/participant.ex:192 lib/graphql/resolvers/person.ex:157
|
||||
#: lib/graphql/resolvers/person.ex:191 lib/graphql/resolvers/person.ex:256 lib/graphql/resolvers/person.ex:288
|
||||