Merge branch 'fixes' into 'master'

Bunch of little fixes

Closes #274, #230, #232, #311, #316 et #315

See merge request framasoft/mobilizon!322
This commit is contained in:
Thomas Citharel 2019-11-18 19:13:51 +01:00
commit 792a2deddb
19 changed files with 1629 additions and 1266 deletions

View file

@ -55,7 +55,7 @@
"@vue/cli-plugin-typescript": "^4.0.3", "@vue/cli-plugin-typescript": "^4.0.3",
"@vue/cli-plugin-unit-mocha": "^4.0.3", "@vue/cli-plugin-unit-mocha": "^4.0.3",
"@vue/cli-service": "^4.0.3", "@vue/cli-service": "^4.0.3",
"@vue/eslint-config-typescript": "^4.0.0", "@vue/eslint-config-typescript": "^5.0.0",
"@vue/test-utils": "^1.0.0-beta.29", "@vue/test-utils": "^1.0.0-beta.29",
"apollo-link-error": "^1.1.12", "apollo-link-error": "^1.1.12",
"chai": "^4.2.0", "chai": "^4.2.0",
@ -67,8 +67,8 @@
"tslint": "^5.20.0", "tslint": "^5.20.0",
"tslint-config-airbnb": "^5.11.2", "tslint-config-airbnb": "^5.11.2",
"typescript": "^3.6.3", "typescript": "^3.6.3",
"vue-cli-plugin-styleguidist": "^3.25.0", "vue-cli-plugin-styleguidist": "^4.0.1",
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0", "vue-cli-plugin-webpack-bundle-analyzer": "^2.0.0",
"vue-i18n-extract": "^1.0.2", "vue-i18n-extract": "^1.0.2",
"vue-svg-inline-loader": "^1.3.0", "vue-svg-inline-loader": "^1.3.0",
"vue-template-compiler": "^2.6.10", "vue-template-compiler": "^2.6.10",

View file

@ -387,6 +387,7 @@ export default class EditorComponent extends Vue {
placement: 'top-start', placement: 'top-start',
inertia: true, inertia: true,
duration: [400, 200], duration: [400, 200],
// @ts-ignore for some reason
showOnInit: true, showOnInit: true,
arrow: true, arrow: true,
arrowType: 'round', arrowType: 'round',

View file

@ -70,7 +70,7 @@ query {
}`; }`;
export const CURRENT_ACTOR_CLIENT = gql` export const CURRENT_ACTOR_CLIENT = gql`
query { query currentActor {
currentActor @client { currentActor @client {
id, id,
avatar { avatar {

View file

@ -289,6 +289,7 @@ export const EDIT_EVENT = gql`
$picture: PictureInput, $picture: PictureInput,
$onlineAddress: String, $onlineAddress: String,
$phoneAddress: String, $phoneAddress: String,
$organizerActorId: ID,
$category: String, $category: String,
$physicalAddress: AddressInput, $physicalAddress: AddressInput,
$options: EventOptionsInput, $options: EventOptionsInput,
@ -307,6 +308,7 @@ export const EDIT_EVENT = gql`
picture: $picture, picture: $picture,
onlineAddress: $onlineAddress, onlineAddress: $onlineAddress,
phoneAddress: $phoneAddress, phoneAddress: $phoneAddress,
organizerActorId: $organizerActorId,
category: $category, category: $category,
physicalAddress: $physicalAddress physicalAddress: $physicalAddress
options: $options, options: $options,

View file

@ -0,0 +1,35 @@
import { Component, Mixins, Vue } from 'vue-property-decorator';
import { Person } from '@/types/actor';
@Component
export default class IdentityEditionMixin extends Mixins(Vue) {
identity = new Person();
oldDisplayName: string | null = null;
autoUpdateUsername(newDisplayName: string | null) {
const oldUsername = IdentityEditionMixin.convertToUsername(this.oldDisplayName);
if (this.identity.preferredUsername === oldUsername) {
this.identity.preferredUsername = IdentityEditionMixin.convertToUsername(newDisplayName);
}
this.oldDisplayName = newDisplayName;
}
private static convertToUsername(value: string | null) {
if (!value) return '';
// https://stackoverflow.com/a/37511463
return value.toLocaleLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/ /g, '_')
.replace(/[^a-z0-9_]/g, '')
;
}
validateUsername() {
return this.identity.preferredUsername === IdentityEditionMixin.convertToUsername(this.identity.preferredUsername);
}
}

View file

@ -10,7 +10,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { IActor } from '@/types/actor'; import { IActor } from '@/types/actor';
import IdentityPicker from './IdentityPicker.vue'; import IdentityPicker from './IdentityPicker.vue';
@ -22,6 +22,11 @@ export default class IdentityPickerWrapper extends Vue {
isComponentModalActive: boolean = false; isComponentModalActive: boolean = false;
currentIdentity: IActor = this.value; currentIdentity: IActor = this.value;
@Watch('value')
updateCurrentActor(value) {
this.currentIdentity = value;
}
relay(identity: IActor) { relay(identity: IActor) {
this.currentIdentity = identity; this.currentIdentity = identity;
this.$emit('input', identity); this.$emit('input', identity);

View file

@ -9,6 +9,10 @@
{{ $t('To achieve your registration, please create a first identity profile.')}} {{ $t('To achieve your registration, please create a first identity profile.')}}
</b-message> </b-message>
<form v-if="!validationSent" @submit.prevent="submit"> <form v-if="!validationSent" @submit.prevent="submit">
<b-field :label="$t('Display name')">
<b-input aria-required="true" required v-model="identity.name" @input="autoUpdateUsername($event)"/>
</b-field>
<b-field <b-field
:label="$t('Username')" :label="$t('Username')"
:type="errors.preferred_username ? 'is-danger' : null" :type="errors.preferred_username ? 'is-danger' : null"
@ -19,7 +23,7 @@
aria-required="true" aria-required="true"
required required
expanded expanded
v-model="person.preferredUsername" v-model="identity.preferredUsername"
/> />
<p class="control"> <p class="control">
<span class="button is-static">@{{ host }}</span> <span class="button is-static">@{{ host }}</span>
@ -27,12 +31,8 @@
</b-field> </b-field>
</b-field> </b-field>
<b-field :label="$t('Displayed name')">
<b-input v-model="person.name"/>
</b-field>
<b-field :label="$t('Description')"> <b-field :label="$t('Description')">
<b-input type="textarea" v-model="person.summary"/> <b-input type="textarea" v-model="identity.summary"/>
</b-field> </b-field>
<p class="control has-text-centered"> <p class="control has-text-centered">
@ -45,7 +45,7 @@
<div v-if="validationSent && !userAlreadyActivated"> <div v-if="validationSent && !userAlreadyActivated">
<b-message title="Success" type="is-success" closable="false"> <b-message title="Success" type="is-success" closable="false">
<h2 class="title"> <h2 class="title">
{{ $t('Your account is nearly ready, {username}', { username: person.preferredUsername }) }} {{ $t('Your account is nearly ready, {username}', { username: identity.preferredUsername }) }}
</h2> </h2>
<p> <p>
{{ $t('A validation email was sent to {email}', { email }) }} {{ $t('A validation email was sent to {email}', { email }) }}
@ -61,22 +61,22 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop } from 'vue-property-decorator';
import { IPerson, Person } from '@/types/actor'; import { IPerson } from '@/types/actor';
import { IDENTITIES, REGISTER_PERSON } from '@/graphql/actor'; import { IDENTITIES, REGISTER_PERSON } from '@/graphql/actor';
import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint'; import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint';
import { RouteName } from '@/router'; import { RouteName } from '@/router';
import { changeIdentity } from '@/utils/auth'; import { changeIdentity } from '@/utils/auth';
import { ICurrentUser } from '@/types/current-user.model'; import { mixins } from 'vue-class-component';
import identityEditionMixin from '@/mixins/identityEdition';
@Component @Component
export default class Register extends Vue { export default class Register extends mixins(identityEditionMixin) {
@Prop({ type: String, required: true }) email!: string; @Prop({ type: String, required: true }) email!: string;
@Prop({ type: Boolean, required: false, default: false }) userAlreadyActivated!: boolean; @Prop({ type: Boolean, required: false, default: false }) userAlreadyActivated!: boolean;
host?: string = MOBILIZON_INSTANCE_HOST; host?: string = MOBILIZON_INSTANCE_HOST;
person: IPerson = new Person();
errors: object = {}; errors: object = {};
validationSent: boolean = false; validationSent: boolean = false;
sendingValidation: boolean = false; sendingValidation: boolean = false;
@ -94,7 +94,7 @@ export default class Register extends Vue {
this.errors = {}; this.errors = {};
const { data } = await this.$apollo.mutate<{ registerPerson: IPerson }>({ const { data } = await this.$apollo.mutate<{ registerPerson: IPerson }>({
mutation: REGISTER_PERSON, mutation: REGISTER_PERSON,
variables: Object.assign({ email: this.email }, this.person), variables: Object.assign({ email: this.email }, this.identity),
update: (store, { data }) => { update: (store, { data }) => {
if (this.userAlreadyActivated) { if (this.userAlreadyActivated) {
const identitiesData = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES }); const identitiesData = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES });

View file

@ -7,13 +7,13 @@
<picture-upload v-model="avatarFile" class="picture-upload"></picture-upload> <picture-upload v-model="avatarFile" class="picture-upload"></picture-upload>
<b-field :label="$t('Display name')"> <b-field horizontal :label="$t('Display name')">
<b-input aria-required="true" required v-model="identity.name" @input="autoUpdateUsername($event)"/> <b-input aria-required="true" required v-model="identity.name" @input="autoUpdateUsername($event)"/>
</b-field> </b-field>
<b-field :label="$t('Username')"> <b-field horizontal custom-class="username-field" expanded :label="$t('Username')" :message="message">
<b-field> <b-field expanded>
<b-input aria-required="true" required v-model="identity.preferredUsername" :disabled="isUpdate"/> <b-input aria-required="true" required v-model="identity.preferredUsername" :disabled="isUpdate" :use-html5-validation="!isUpdate" pattern="[a-z0-9_]+"/>
<p class="control"> <p class="control">
<span class="button is-static">@{{ getInstanceHost() }}</span> <span class="button is-static">@{{ getInstanceHost() }}</span>
@ -21,7 +21,7 @@
</b-field> </b-field>
</b-field> </b-field>
<b-field :label="$t('Description')"> <b-field horizontal :label="$t('Description')">
<b-input type="textarea" aria-required="false" v-model="identity.summary"/> <b-input type="textarea" aria-required="false" v-model="identity.summary"/>
</b-field> </b-field>
@ -77,10 +77,14 @@
cursor: pointer; cursor: pointer;
margin-top: 15px; margin-top: 15px;
} }
.username-field + .field {
margin-bottom: 0;
}
</style> </style>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; import { Component, Prop, Watch } from 'vue-property-decorator';
import { import {
CREATE_PERSON, CREATE_PERSON,
CURRENT_ACTOR_CLIENT, CURRENT_ACTOR_CLIENT,
@ -96,6 +100,8 @@ import { Dialog } from 'buefy/dist/components/dialog';
import { RouteName } from '@/router'; import { RouteName } from '@/router';
import { buildFileFromIPicture, buildFileVariable, readFileAsync } from '@/utils/image'; import { buildFileFromIPicture, buildFileVariable, readFileAsync } from '@/utils/image';
import { changeIdentity } from '@/utils/auth'; import { changeIdentity } from '@/utils/auth';
import { mixins } from 'vue-class-component';
import identityEditionMixin from '@/mixins/identityEdition';
@Component({ @Component({
components: { components: {
@ -108,18 +114,21 @@ import { changeIdentity } from '@/utils/auth';
}, },
}, },
}) })
export default class EditIdentity extends Vue { export default class EditIdentity extends mixins(identityEditionMixin) {
@Prop({ type: Boolean }) isUpdate!: boolean; @Prop({ type: Boolean }) isUpdate!: boolean;
errors: string[] = []; errors: string[] = [];
identityName!: string | undefined; identityName!: string | undefined;
avatarFile: File | null = null; avatarFile: File | null = null;
identity = new Person();
private oldDisplayName: string | null = null;
private currentActor: IPerson | null = null; private currentActor: IPerson | null = null;
get message() {
if (this.isUpdate) return null;
return this.$t('Only alphanumeric characters and underscores are supported.');
}
@Watch('isUpdate') @Watch('isUpdate')
async isUpdateChanged () { async isUpdateChanged () {
this.resetFields(); this.resetFields();
@ -153,16 +162,6 @@ export default class EditIdentity extends Vue {
return this.createIdentity(); return this.createIdentity();
} }
autoUpdateUsername(newDisplayName: string | null) {
const oldUsername = this.convertToUsername(this.oldDisplayName);
if (this.identity.preferredUsername === oldUsername) {
this.identity.preferredUsername = this.convertToUsername(newDisplayName);
}
this.oldDisplayName = newDisplayName;
}
/** /**
* Delete an identity * Delete an identity
*/ */
@ -309,18 +308,6 @@ export default class EditIdentity extends Vue {
} }
} }
private convertToUsername(value: string | null) {
if (!value) return '';
// https://stackoverflow.com/a/37511463
return value.toLocaleLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/ /g, '_')
.replace(/[^a-z0-9._]/g, '')
;
}
private async buildVariables() { private async buildVariables() {
const avatarObj = buildFileVariable(this.avatarFile, 'avatar', `${this.identity.preferredUsername}'s avatar`); const avatarObj = buildFileVariable(this.avatarFile, 'avatar', `${this.identity.preferredUsername}'s avatar`);
const res = Object.assign({}, this.identity, avatarObj); const res = Object.assign({}, this.identity, avatarObj);

File diff suppressed because it is too large Load diff

View file

@ -203,14 +203,9 @@ defmodule Mobilizon.Actors.Actor do
actor actor
|> cast(attrs, @attrs) |> cast(attrs, @attrs)
|> build_urls() |> build_urls()
|> cast_embed(:avatar) |> common_changeset()
|> cast_embed(:banner)
|> unique_username_validator() |> unique_username_validator()
|> validate_required(@required_attrs) |> validate_required(@required_attrs)
|> unique_constraint(:preferred_username,
name: :actors_preferred_username_domain_type_index
)
|> unique_constraint(:url, name: :actors_url_index)
end end
@doc false @doc false
@ -218,13 +213,8 @@ defmodule Mobilizon.Actors.Actor do
def update_changeset(%__MODULE__{} = actor, attrs) do def update_changeset(%__MODULE__{} = actor, attrs) do
actor actor
|> cast(attrs, @update_attrs) |> cast(attrs, @update_attrs)
|> cast_embed(:avatar) |> common_changeset()
|> cast_embed(:banner)
|> validate_required(@update_required_attrs) |> validate_required(@update_required_attrs)
|> unique_constraint(:preferred_username,
name: :actors_preferred_username_domain_type_index
)
|> unique_constraint(:url, name: :actors_url_index)
end end
@doc """ @doc """
@ -235,13 +225,8 @@ defmodule Mobilizon.Actors.Actor do
actor actor
|> cast(attrs, @registration_attrs) |> cast(attrs, @registration_attrs)
|> build_urls() |> build_urls()
|> cast_embed(:avatar) |> common_changeset()
|> cast_embed(:banner)
|> unique_username_validator() |> unique_username_validator()
|> unique_constraint(:preferred_username,
name: :actors_preferred_username_domain_type_index
)
|> unique_constraint(:url, name: :actors_url_index)
|> validate_required(@registration_required_attrs) |> validate_required(@registration_required_attrs)
end end
@ -254,13 +239,8 @@ defmodule Mobilizon.Actors.Actor do
%__MODULE__{} %__MODULE__{}
|> cast(attrs, @remote_actor_creation_attrs) |> cast(attrs, @remote_actor_creation_attrs)
|> validate_required(@remote_actor_creation_required_attrs) |> validate_required(@remote_actor_creation_required_attrs)
|> cast_embed(:avatar) |> common_changeset()
|> cast_embed(:banner)
|> unique_username_validator() |> unique_username_validator()
|> unique_constraint(:preferred_username,
name: :actors_preferred_username_domain_type_index
)
|> unique_constraint(:url, name: :actors_url_index)
|> validate_length(:summary, max: 5000) |> validate_length(:summary, max: 5000)
|> validate_length(:preferred_username, max: 100) |> validate_length(:preferred_username, max: 100)
@ -269,6 +249,16 @@ defmodule Mobilizon.Actors.Actor do
changeset changeset
end end
@spec common_changeset(Ecto.Changeset.t()) :: Ecto.Changeset.t()
defp common_changeset(%Ecto.Changeset{} = changeset) do
changeset
|> cast_embed(:avatar)
|> cast_embed(:banner)
|> unique_constraint(:url, name: :actors_url_index)
|> unique_constraint(:preferred_username, name: :actors_preferred_username_domain_type_index)
|> validate_format(:preferred_username, ~r/[a-z0-9_]+/)
end
@doc """ @doc """
Changeset for relay creation. Changeset for relay creation.
""" """

View file

@ -128,7 +128,6 @@ defmodule Mobilizon.Events.Event do
|> common_changeset(attrs) |> common_changeset(attrs)
|> put_creator_if_published(:create) |> put_creator_if_published(:create)
|> validate_required(@required_attrs) |> validate_required(@required_attrs)
|> validate_lengths()
end end
@doc false @doc false
@ -139,7 +138,6 @@ defmodule Mobilizon.Events.Event do
|> common_changeset(attrs) |> common_changeset(attrs)
|> put_creator_if_published(:update) |> put_creator_if_published(:update)
|> validate_required(@update_required_attrs) |> validate_required(@update_required_attrs)
|> validate_lengths()
end end
@spec common_changeset(Changeset.t(), map) :: Changeset.t() @spec common_changeset(Changeset.t(), map) :: Changeset.t()
@ -149,6 +147,8 @@ defmodule Mobilizon.Events.Event do
|> put_tags(attrs) |> put_tags(attrs)
|> put_address(attrs) |> put_address(attrs)
|> put_picture(attrs) |> put_picture(attrs)
|> validate_lengths()
|> validate_end_time()
end end
@spec validate_lengths(Changeset.t()) :: Changeset.t() @spec validate_lengths(Changeset.t()) :: Changeset.t()
@ -162,6 +162,20 @@ defmodule Mobilizon.Events.Event do
|> validate_length(:slug, min: 3, max: 200) |> validate_length(:slug, min: 3, max: 200)
end end
defp validate_end_time(%Changeset{} = changeset) do
case fetch_field(changeset, :begins_on) do
{_, begins_on} ->
validate_change(changeset, :ends_on, fn :ends_on, ends_on ->
if begins_on > ends_on,
do: [ends_on: "ends_on cannot be set before begins_on"],
else: []
end)
:error ->
changeset
end
end
@doc """ @doc """
Checks whether an event can be managed. Checks whether an event can be managed.
""" """

View file

@ -275,6 +275,9 @@ defmodule MobilizonWeb.Resolvers.Event do
{:is_owned, nil} -> {:is_owned, nil} ->
{:error, "Organizer actor id is not owned by the user"} {:error, "Organizer actor id is not owned by the user"}
{:error, _, %Ecto.Changeset{} = error, _} ->
{:error, error}
{:error, %Ecto.Changeset{} = error} -> {:error, %Ecto.Changeset{} = error} ->
{:error, error} {:error, error}
end end
@ -295,8 +298,9 @@ defmodule MobilizonWeb.Resolvers.Event do
# See https://github.com/absinthe-graphql/absinthe/issues/490 # See https://github.com/absinthe-graphql/absinthe/issues/490
with args <- Map.put(args, :options, args[:options] || %{}), with args <- Map.put(args, :options, args[:options] || %{}),
{:ok, %Event{} = event} <- Events.get_event_with_preload(event_id), {: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} <- {:is_owned, %Actor{} = organizer_actor} <-
User.owns_actor(user, event.organizer_actor_id), User.owns_actor(user, organizer_actor_id),
args <- Map.put(args, :organizer_actor, organizer_actor), args <- Map.put(args, :organizer_actor, organizer_actor),
{:ok, %Activity{data: %{"object" => %{"type" => "Event"}}}, %Event{} = event} <- {:ok, %Activity{data: %{"object" => %{"type" => "Event"}}}, %Event{} = event} <-
MobilizonWeb.API.Events.update_event(args, event) do MobilizonWeb.API.Events.update_event(args, event) do
@ -307,6 +311,9 @@ defmodule MobilizonWeb.Resolvers.Event do
{:is_owned, nil} -> {:is_owned, nil} ->
{:error, "User doesn't own actor"} {:error, "User doesn't own actor"}
{:error, _, %Ecto.Changeset{} = error, _} ->
{:error, error}
end end
end end

View file

@ -299,6 +299,7 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:online_address, :string) arg(:online_address, :string)
arg(:phone_address, :string) arg(:phone_address, :string)
arg(:organizer_actor_id, :id)
arg(:category, :string) arg(:category, :string)
arg(:physical_address, :address_input) arg(:physical_address, :address_input)
arg(:options, :event_options_input) arg(:options, :event_options_input)

View file

@ -93,8 +93,6 @@ defmodule Mobilizon.Service.ActivityPub do
{:ok, Actors.get_actor_by_url!(actor_url, true)} {:ok, Actors.get_actor_by_url!(actor_url, true)}
e -> e ->
require Logger
Logger.error(inspect(e))
{:error, e} {:error, e}
end end
end end
@ -135,14 +133,13 @@ defmodule Mobilizon.Service.ActivityPub do
Logger.debug("creating an activity") Logger.debug("creating an activity")
Logger.debug(inspect(args)) Logger.debug(inspect(args))
{:ok, entity, create_data} = with {:ok, entity, create_data} <-
case type do (case type do
:event -> create_event(args, additional) :event -> create_event(args, additional)
:comment -> create_comment(args, additional) :comment -> create_comment(args, additional)
:group -> create_group(args, additional) :group -> create_group(args, additional)
end end),
{:ok, activity} <- create_activity(create_data, local),
with {:ok, activity} <- create_activity(create_data, local),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity, entity} {:ok, activity, entity}
else else
@ -167,13 +164,12 @@ defmodule Mobilizon.Service.ActivityPub do
Logger.debug("updating an activity") Logger.debug("updating an activity")
Logger.debug(inspect(args)) Logger.debug(inspect(args))
{:ok, entity, update_data} = with {:ok, entity, update_data} <-
case type do (case type do
:event -> update_event(old_entity, args, additional) :event -> update_event(old_entity, args, additional)
:actor -> update_actor(old_entity, args, additional) :actor -> update_actor(old_entity, args, additional)
end end),
{:ok, activity} <- create_activity(update_data, local),
with {:ok, activity} <- create_activity(update_data, local),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity, entity} {:ok, activity, entity}
else else

View file

@ -339,8 +339,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
ActivityPub.update(:event, old_event, object_data, false) do ActivityPub.update(:event, old_event, object_data, false) do
{:ok, activity, new_event} {:ok, activity, new_event}
else else
e -> _e ->
Logger.error(inspect(e))
:error :error
end end
end end
@ -442,8 +441,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
:error :error
e -> _e ->
Logger.error(inspect(e))
:error :error
end end
end end

View file

@ -100,7 +100,7 @@ defmodule Mobilizon.Mixfile do
{:ex_cldr_dates_times, "~> 2.0"}, {:ex_cldr_dates_times, "~> 2.0"},
{:ex_optimizer, "~> 0.1"}, {:ex_optimizer, "~> 0.1"},
{:progress_bar, "~> 2.0"}, {:progress_bar, "~> 2.0"},
{:oban, "~> 0.10"}, {:oban, "~> 0.11.1"},
# Dev and test dependencies # Dev and test dependencies
{:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]}, {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]},
{:ex_machina, "~> 2.3", only: [:dev, :test]}, {:ex_machina, "~> 2.3", only: [:dev, :test]},

View file

@ -14,7 +14,7 @@
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"cldr_utils": {:hex, :cldr_utils, "2.5.0", "2a15b82b5b56bba99b897ff5801a5b1dcbce425b6430445e97d024a9999afb03", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "cldr_utils": {:hex, :cldr_utils, "2.5.0", "2a15b82b5b56bba99b897ff5801a5b1dcbce425b6430445e97d024a9999afb03", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"comeonin": {:hex, :comeonin, "5.1.2", "fbbbbbfcf0f0e9900c0336d16c8d462edf838ba1759577e29cc5fbd7c28a4540", [:mix], [], "hexpm"}, "comeonin": {:hex, :comeonin, "5.1.3", "4c9880ed348cc0330c74086b4383ffb0b5a599aa603416497b7374c168cae340", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cors_plug": {:hex, :cors_plug, "2.0.0", "238ddb479f92b38f6dc1ae44b8d81f0387f9519101a6da442d543ab70ee0e482", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "cors_plug": {:hex, :cors_plug, "2.0.0", "238ddb479f92b38f6dc1ae44b8d81f0387f9519101a6da442d543ab70ee0e482", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
@ -34,8 +34,8 @@
"erlex": {:hex, :erlex, "0.2.5", "e51132f2f472e13d606d808f0574508eeea2030d487fc002b46ad97e738b0510", [:mix], [], "hexpm"}, "erlex": {:hex, :erlex, "0.2.5", "e51132f2f472e13d606d808f0574508eeea2030d487fc002b46ad97e738b0510", [:mix], [], "hexpm"},
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"},
"ex_cldr": {:hex, :ex_cldr, "2.11.1", "8e500a88b68be01a97315bea394d593e74e1035c0a5dc6f0b8281423857ec9b3", [:mix], [{:cldr_utils, "~> 2.3", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr": {:hex, :ex_cldr, "2.11.1", "8e500a88b68be01a97315bea394d593e74e1035c0a5dc6f0b8281423857ec9b3", [:mix], [{:cldr_utils, "~> 2.3", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.4.0", "c7adf1e752b0cbad6f565246a583f1d056ad05fdc0c7fb8b66d498d1b381225f", [:mix], [{:ex_cldr, "~> 2.8", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.4", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_units, "~> 2.0", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.5.1", "136bc95c87791bfc558d19182e53790263981484085ffa23ceb9122ad52001c9", [:mix], [{:ex_cldr, "~> 2.8", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.4", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_units, "~> 2.0", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.3.0", "bffae489416b8b05d4683403263f5d62aae17de70c24ff915a533541fea514de", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.4.1", "a8e8330a6d0712b8bb34c5e3759311da1d53fa8bebef163d72615f0ea60c0738", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.2.3", "4a82f6af48f55c92c0d28be066e5b2451e807e3f49246d08845af664fd7cb712", [:mix], [{:ex_cldr, "~> 2.8", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_calendars, "~> 1.2", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.6", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.2.3", "4a82f6af48f55c92c0d28be066e5b2451e807e3f49246d08845af664fd7cb712", [:mix], [{:ex_cldr, "~> 2.8", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_calendars, "~> 1.2", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.6", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.9.0", "ffba3ba8cfa41194e57cc38f0cc78f83956ce5c1822b1e4d5f64394cb927ba2c", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.11", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.3", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.9.0", "ffba3ba8cfa41194e57cc38f0cc78f83956ce5c1822b1e4d5f64394cb927ba2c", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.11", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.3", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ex_crypto": {:hex, :ex_crypto, "0.10.0", "af600a89b784b36613a989da6e998c1b200ff1214c3cfbaf8deca4aa2f0a1739", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "ex_crypto": {:hex, :ex_crypto, "0.10.0", "af600a89b784b36613a989da6e998c1b200ff1214c3cfbaf8deca4aa2f0a1739", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
@ -64,7 +64,7 @@
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]}, "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
"httpoison": {:hex, :httpoison, "1.6.1", "2ce5bf6e535cd0ab02e905ba8c276580bab80052c5c549f53ddea52d72e81f33", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"icalendar": {:git, "https://github.com/tcitworld/icalendar.git", "bd08e872c125f70a87c3ac7d87ea2f22a5577059", []}, "icalendar": {:git, "https://github.com/tcitworld/icalendar.git", "bd08e872c125f70a87c3ac7d87ea2f22a5577059", []},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
@ -79,16 +79,16 @@
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mimetype_parser": {:hex, :mimetype_parser, "0.1.3", "628ac9fe56aa7edcedb534d68397dd66674ab82493c8ebe39acb9a19b666099d", [:mix], [], "hexpm"}, "mimetype_parser": {:hex, :mimetype_parser, "0.1.3", "628ac9fe56aa7edcedb534d68397dd66674ab82493c8ebe39acb9a19b666099d", [:mix], [], "hexpm"},
"mix_test_watch": {:hex, :mix_test_watch, "1.0.1", "ae6fc45bbc80b826046fb84208df4b06035e10fae6d44d0cb48c5a2f92ee2e1d", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"}, "mix_test_watch": {:hex, :mix_test_watch, "1.0.2", "34900184cbbbc6b6ed616ed3a8ea9b791f9fd2088419352a6d3200525637f785", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"},
"mmdb2_decoder": {:hex, :mmdb2_decoder, "1.1.0", "2e2347521bb3bf6b81b9ee58d3be2199cb68ea42dcbafcd0d8eb40214d2844cf", [:mix], [], "hexpm"}, "mmdb2_decoder": {:hex, :mmdb2_decoder, "1.1.0", "2e2347521bb3bf6b81b9ee58d3be2199cb68ea42dcbafcd0d8eb40214d2844cf", [:mix], [], "hexpm"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mogrify": {:hex, :mogrify, "0.7.3", "1494ee739f6e90de158dec4d4edee2d854d2f2d06a522e943f996ae176bca53d", [:mix], [], "hexpm"}, "mogrify": {:hex, :mogrify, "0.7.3", "1494ee739f6e90de158dec4d4edee2d854d2f2d06a522e943f996ae176bca53d", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.2", "1d71150d5293d703a9c38d4329da57d3935faed2031d64bc19e77b654ef2d177", [:mix], [], "hexpm"},
"oban": {:hex, :oban, "0.10.1", "c2ca0a413fb66b21dd58c7cb67fd80b01e9d79a0fbb28573f110057e7fdc3807", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "oban": {:hex, :oban, "0.11.1", "e34964fad7f188c2c3d006485601a8897e537f7b88a31928be2833ae1cab59af", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.11", "d112c862f6959f98e6e915c3b76c7a87ca3efd075850c8daa7c3c7a609014b0d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.1", "274a4b07c4adbdd7785d45a8b0bb57634d0b4f45b18d2c508b26c0344bd59b8f", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.1", "274a4b07c4adbdd7785d45a8b0bb57634d0b4f45b18d2c508b26c0344bd59b8f", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"},

View file

@ -1,5 +1,5 @@
# source: http://localhost:4000/api # source: http://localhost:4000/api
# timestamp: Fri Nov 08 2019 17:20:47 GMT+0100 (Central European Standard Time) # timestamp: Mon Nov 18 2019 16:00:35 GMT+0100 (Central European Standard Time)
schema { schema {
query: RootQueryType query: RootQueryType
@ -1081,6 +1081,7 @@ type RootMutationType {
joinOptions: EventJoinOptions = FREE joinOptions: EventJoinOptions = FREE
onlineAddress: String onlineAddress: String
options: EventOptionsInput options: EventOptionsInput
organizerActorId: ID
phoneAddress: String phoneAddress: String
physicalAddress: AddressInput physicalAddress: AddressInput
@ -1178,7 +1179,7 @@ type RootQueryType {
reports(limit: Int = 10, page: Int = 1, status: ReportStatus = OPEN): [Report] reports(limit: Int = 10, page: Int = 1, status: ReportStatus = OPEN): [Report]
"""Reverse geocode coordinates""" """Reverse geocode coordinates"""
reverseGeocode(latitude: Float!, longitude: Float!): [Address] reverseGeocode(latitude: Float!, locale: String = "en", longitude: Float!, zoom: Int = 15): [Address]
"""Search for an address""" """Search for an address"""
searchAddress(limit: Int = 10, locale: String = "en", page: Int = 1, query: String!): [Address] searchAddress(limit: Int = 10, locale: String = "en", page: Int = 1, query: String!): [Address]

View file

@ -95,6 +95,40 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
"Organizer actor id is not owned by the user" "Organizer actor id is not owned by the user"
end end
test "create_event/3 should check that end time is after start time", %{
conn: conn,
actor: actor,
user: user
} do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second)
ends_on = Timex.shift(begins_on, hours: -2)
mutation = """
mutation {
createEvent(
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.to_iso8601(begins_on)}",
ends_on: "#{DateTime.to_iso8601(ends_on)}",
organizer_actor_id: "#{actor.id}",
category: "birthday"
) {
id,
title,
uuid
}
}
"""
res =
conn
|> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert hd(json_response(res, 200)["errors"])["message"] ==
"ends_on cannot be set before begins_on"
end
test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do
mutation = """ mutation = """
mutation { mutation {
@ -661,6 +695,39 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
assert hd(json_response(res, 200)["errors"])["message"] == "User doesn't own actor" assert hd(json_response(res, 200)["errors"])["message"] == "User doesn't own actor"
end end
test "update_event/3 should check end time is after the beginning time", %{
conn: conn,
actor: actor,
user: user
} do
event = insert(:event, organizer_actor: actor)
mutation = """
mutation {
updateEvent(
title: "my event updated",
ends_on: "#{Timex.shift(event.begins_on, hours: -2)}",
event_id: #{event.id}
) {
title,
uuid,
tags {
title,
slug
}
}
}
"""
res =
conn
|> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert hd(json_response(res, 200)["errors"])["message"] ==
"ends_on cannot be set before begins_on"
end
test "update_event/3 updates an event", %{conn: conn, actor: actor, user: user} do test "update_event/3 updates an event", %{conn: conn, actor: actor, user: user} do
event = insert(:event, organizer_actor: actor) event = insert(:event, organizer_actor: actor)
_creator = insert(:participant, event: event, actor: actor, role: :creator) _creator = insert(:participant, event: event, actor: actor, role: :creator)