Merge branch 'bugs' into 'master'

Various bugs

Closes #827

See merge request framasoft/mobilizon!1029
This commit is contained in:
Thomas Citharel 2021-08-13 11:02:18 +00:00
commit 423209aa2d
10 changed files with 564 additions and 521 deletions

View File

@ -72,14 +72,14 @@
"@types/prosemirror-view": "^1.11.4",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vue/cli-plugin-babel": "~5.0.0-beta.2",
"@vue/cli-plugin-e2e-cypress": "~5.0.0-beta.2",
"@vue/cli-plugin-eslint": "~5.0.0-beta.2",
"@vue/cli-plugin-pwa": "~5.0.0-beta.2",
"@vue/cli-plugin-router": "~5.0.0-beta.2",
"@vue/cli-plugin-typescript": "~5.0.0-beta.2",
"@vue/cli-plugin-unit-jest": "~5.0.0-beta.2",
"@vue/cli-service": "~5.0.0-beta.2",
"@vue/cli-plugin-babel": "~5.0.0-beta.3",
"@vue/cli-plugin-e2e-cypress": "~5.0.0-beta.3",
"@vue/cli-plugin-eslint": "~5.0.0-beta.3",
"@vue/cli-plugin-pwa": "~5.0.0-beta.3",
"@vue/cli-plugin-router": "~5.0.0-beta.3",
"@vue/cli-plugin-typescript": "~5.0.0-beta.3",
"@vue/cli-plugin-unit-jest": "~5.0.0-beta.3",
"@vue/cli-service": "~5.0.0-beta.3",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"@vue/test-utils": "^1.1.0",
@ -89,10 +89,11 @@
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.6.0",
"flush-promises": "^1.0.2",
"jest": "^26.6.3",
"jest-junit": "^12.0.0",
"mock-apollo-client": "^1.1.0",
"prettier": "^2.2.1",
"prettier-eslint": "^12.0.0",
"prettier-eslint": "^13.0.0",
"sass": "^1.34.1",
"sass-loader": "^12.0.0",
"ts-jest": "^26.5.3",

View File

@ -207,7 +207,8 @@ export class EventModel implements IEvent {
}
}
function removeTypeName(entity: any): any {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function removeTypeName(entity: any): any {
if (entity?.__typename) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { __typename, ...purgedEntity } = entity;

View File

@ -161,7 +161,7 @@
v-if="config && config.anonymous.participation.allowed"
>
<label class="label">{{ $t("Anonymous participations") }}</label>
<b-switch v-model="event.options.anonymousParticipation">
<b-switch v-model="eventOptions.anonymousParticipation">
{{
$t("I want to allow people to participate without an account.")
}}
@ -200,18 +200,18 @@
<b-numberinput
controls-position="compact"
min="1"
v-model="event.options.maximumAttendeeCapacity"
v-model="eventOptions.maximumAttendeeCapacity"
/>
</b-field>
<!--
<b-field>
<b-switch v-model="event.options.showRemainingAttendeeCapacity">
<b-switch v-model="eventOptions.showRemainingAttendeeCapacity">
{{ $t('Show remaining number of places') }}
</b-switch>
</b-field>
<b-field>
<b-switch v-model="event.options.showParticipationPrice">
<b-switch v-model="eventOptions.showParticipationPrice">
{{ $t('Display participation price') }}
</b-switch>
</b-field>-->
@ -221,7 +221,7 @@
<div class="field">
<b-radio
v-model="event.options.commentModeration"
v-model="eventOptions.commentModeration"
name="commentModeration"
:native-value="CommentModeration.ALLOW_ALL"
>{{ $t("Allow all comments from users with accounts") }}</b-radio
@ -229,7 +229,7 @@
</div>
<!-- <div class="field">-->
<!-- <b-radio v-model="event.options.commentModeration"-->
<!-- <b-radio v-model="eventOptions.commentModeration"-->
<!-- name="commentModeration"-->
<!-- :native-value="CommentModeration.MODERATED">-->
<!-- {{ $t('Moderated comments (shown after approval)') }}-->
@ -238,7 +238,7 @@
<div class="field">
<b-radio
v-model="event.options.commentModeration"
v-model="eventOptions.commentModeration"
name="commentModeration"
:native-value="CommentModeration.CLOSED"
>{{ $t("Close comments for all (except for admins)") }}</b-radio
@ -291,12 +291,12 @@
</header>
<section class="modal-card-body">
<b-field :label="$t('Event page settings')">
<b-switch v-model="event.options.showStartTime">{{
<b-switch v-model="eventOptions.showStartTime">{{
$t("Show the time when the event begins")
}}</b-switch>
</b-field>
<b-field>
<b-switch v-model="event.options.showEndTime">{{
<b-switch v-model="eventOptions.showEndTime">{{
$t("Show the time when the event ends")
}}</b-switch>
</b-field>
@ -481,7 +481,12 @@ import {
EVENT_PERSON_PARTICIPATION,
FETCH_EVENT,
} from "../../graphql/event";
import { EventModel, IEvent, toEditJSON } from "../../types/event.model";
import {
EventModel,
IEvent,
removeTypeName,
toEditJSON,
} from "../../types/event.model";
import {
CURRENT_ACTOR_CLIENT,
IDENTITIES,
@ -513,6 +518,7 @@ import {
InternalRefetchQueriesInclude,
} from "@apollo/client/core";
import cloneDeep from "lodash/cloneDeep";
import { IEventOptions } from "@/types/event-options.model";
const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
@ -668,6 +674,14 @@ export default class EditEvent extends Vue {
return this.event.attributedTo?.id !== undefined;
}
get eventOptions(): IEventOptions {
return removeTypeName(cloneDeep(this.event.options));
}
set eventOptions(options: IEventOptions) {
this.event.options = options;
}
async mounted(): Promise<void> {
this.observer = new IntersectionObserver(
(entries) => {
@ -685,7 +699,7 @@ export default class EditEvent extends Vue {
this.observer.observe(this.$refs.bottomObserver as Element);
this.pictureFile = await buildFileFromIMedia(this.event.picture);
this.limitedPlaces = this.event.options.maximumAttendeeCapacity > 0;
this.limitedPlaces = this.eventOptions.maximumAttendeeCapacity > 0;
if (!(this.isUpdate || this.isDuplicate)) {
this.initializeEvent();
} else {
@ -913,7 +927,10 @@ export default class EditEvent extends Vue {
* Build variables for Event GraphQL creation query
*/
private async buildVariables() {
let res = toEditJSON(new EventModel(this.event));
let res = {
...toEditJSON(new EventModel(this.event)),
options: this.eventOptions,
};
const organizerActor = this.event.organizerActor?.id
? this.event.organizerActor
: this.organizerActor;
@ -956,12 +973,12 @@ export default class EditEvent extends Vue {
@Watch("limitedPlaces")
updatedEventCapacityOptions(limitedPlaces: boolean): void {
if (!limitedPlaces) {
this.event.options.maximumAttendeeCapacity = 0;
this.event.options.remainingAttendeeCapacity = 0;
this.event.options.showRemainingAttendeeCapacity = false;
this.eventOptions.maximumAttendeeCapacity = 0;
this.eventOptions.remainingAttendeeCapacity = 0;
this.eventOptions.showRemainingAttendeeCapacity = false;
} else {
this.event.options.maximumAttendeeCapacity =
this.event.options.maximumAttendeeCapacity ||
this.eventOptions.maximumAttendeeCapacity =
this.eventOptions.maximumAttendeeCapacity ||
DEFAULT_LIMIT_NUMBER_OF_PLACES;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -870,7 +870,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
when role in [:not_approved, :rejected] do
with %Event{} = event <- Events.get_event_with_preload!(event.id),
{:can_accept_event_join, true} <-
{:can_accept_event_join, can_accept_event_join?(actor_accepting, event)},
{:can_accept_event_join, can_manage_event?(actor_accepting, event)},
{:ok, %Activity{} = activity, %Participant{role: :participant} = participant} <-
ActivityPub.accept(
:join,
@ -918,9 +918,9 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
with {:join_event, {:ok, %Participant{event: event, role: role} = participant}}
when role != :rejected <-
{:join_event, get_participant(join_object, actor_accepting)},
# TODO: The actor that accepts the Join activity may another one that the event organizer ?
# Or maybe for groups it's the group that sends the Accept activity
{:same_actor, true} <- {:same_actor, actor_accepting.id == event.organizer_actor_id},
{:event, %Event{} = event} <- {:event, Events.get_event_with_preload!(event.id)},
{:can_accept_event_reject, true} <-
{:can_accept_event_reject, can_manage_event?(actor_accepting, event)},
{:ok, activity, participant} <-
ActivityPub.reject(:join, participant, false),
:ok <- Participation.send_emails_to_local_user(participant) do
@ -1142,21 +1142,21 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
end
end
defp can_accept_event_join?(
defp can_manage_event?(
%Actor{url: actor_url} = actor,
%Event{attributed_to: %Actor{type: :Group, url: group_url} = _group} = event
) do
actor_url == group_url || Permission.can_update_group_object?(actor, event)
end
defp can_accept_event_join?(
defp can_manage_event?(
%Actor{id: actor_id},
%Event{organizer_actor: %Actor{id: organizer_actor_id}}
) do
organizer_actor_id == actor_id
end
defp can_accept_event_join?(_actor, _event) do
defp can_manage_event?(_actor, _event) do
false
end
end

View File

@ -75,6 +75,7 @@ defmodule Mobilizon.GraphQL.API.Participations do
ActivityPub.reject(
:join,
participation,
true,
%{"actor" => moderator.url}
),
:ok <- Participation.send_emails_to_local_user(participation) do

View File

@ -15,6 +15,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
alias Mobilizon.Federation.ActivityPub.Permission
import Mobilizon.Users.Guards, only: [is_moderator: 1]
import Mobilizon.Web.Gettext
import Mobilizon.GraphQL.Resolvers.Event.Utils
# We limit the max number of events that can be retrieved
@event_max_limit 100
@ -133,14 +134,14 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
List participants for event (through an event request)
"""
def list_participants_for_event(
%Event{id: event_id},
%Event{id: event_id} = event,
%{page: page, limit: limit, roles: roles},
%{context: %{current_user: %User{} = user}} = _resolution
) do
with %Actor{id: actor_id} <- Users.get_actor_for_user(user),
with %Actor{} = actor <- Users.get_actor_for_user(user),
# Check that moderator has right
{:actor_approve_permission, true} <-
{:actor_approve_permission, Events.moderator_for_event?(event_id, actor_id)} do
{:event_can_be_managed, true} <-
{:event_can_be_managed, can_event_be_updated_by?(event, actor)} do
roles =
case roles do
nil ->
@ -159,7 +160,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
participants = Events.list_participants_for_event(event_id, roles, page, limit)
{:ok, participants}
else
{:actor_approve_permission, _} ->
{:event_can_be_managed, _} ->
{:error,
dgettext("errors", "Provided profile doesn't have moderator permissions on this event")}
end
@ -414,29 +415,4 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
{:ok, args}
end
end
defp can_event_be_updated_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Actor{} = actor_member
) do
Permission.can_update_group_object?(actor_member, event)
end
defp can_event_be_updated_by?(
%Event{} = event,
%Actor{id: actor_member_id}
) do
Event.can_be_managed_by?(event, actor_member_id)
end
defp can_event_be_deleted_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Actor{} = actor_member
) do
Permission.can_delete_group_object?(actor_member, event)
end
defp can_event_be_deleted_by?(%Event{} = event, %Actor{id: actor_member_id}) do
Event.can_be_managed_by?(event, actor_member_id)
end
end

View File

@ -0,0 +1,34 @@
defmodule Mobilizon.GraphQL.Resolvers.Event.Utils do
@moduledoc """
Tools to test permission on events
"""
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.Event
alias Mobilizon.Federation.ActivityPub.Permission
def can_event_be_updated_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Actor{} = actor_member
) do
Permission.can_update_group_object?(actor_member, event)
end
def can_event_be_updated_by?(
%Event{} = event,
%Actor{id: actor_member_id}
) do
Event.can_be_managed_by?(event, actor_member_id)
end
def can_event_be_deleted_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Actor{} = actor_member
) do
Permission.can_delete_group_object?(actor_member, event)
end
def can_event_be_deleted_by?(%Event{} = event, %Actor{id: actor_member_id}) do
Event.can_be_managed_by?(event, actor_member_id)
end
end

View File

@ -11,6 +11,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do
alias Mobilizon.Web.Email.Checker
require Logger
import Mobilizon.Web.Gettext
import Mobilizon.GraphQL.Resolvers.Event.Utils
@doc """
Join an event for an regular or anonymous actor
@ -213,15 +214,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do
}
) do
# Check that moderator provided is rightly authenticated
with %Actor{id: moderator_actor_id} = moderator_actor <- Users.get_actor_for_user(user),
with %Actor{} = moderator_actor <- Users.get_actor_for_user(user),
# Check that participation already exists
{:has_participation, %Participant{role: old_role} = participation} <-
{:has_participation, %Participant{role: old_role, event_id: event_id} = participation} <-
{:has_participation, Events.get_participant(participation_id)},
{:same_role, false} <- {:same_role, new_role == old_role},
# Check that moderator has right
{:actor_approve_permission, true} <-
{:actor_approve_permission,
Events.moderator_for_event?(participation.event.id, moderator_actor_id)},
{:event, %Event{} = event} <- {:event, Events.get_event_with_preload!(event_id)},
{:event_can_be_managed, true} <-
{:event_can_be_managed, can_event_be_updated_by?(event, moderator_actor)},
{:ok, _activity, participation} <-
Participations.update(participation, moderator_actor, new_role) do
{:ok, participation}
@ -229,7 +230,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do
{:has_participation, nil} ->
{:error, dgettext("errors", "Participant not found")}
{:actor_approve_permission, _} ->
{:event_can_be_managed, _} ->
{:error,
dgettext("errors", "Provided profile doesn't have moderator permissions on this event")}

View File

@ -24,7 +24,7 @@
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
"earmark_parser": {:hex, :earmark_parser, "1.4.15", "b29e8e729f4aa4a00436580dcc2c9c5c51890613457c193cc8525c388ccb2f06", [:mix], [], "hexpm", "044523d6438ea19c1b8ec877ec221b008661d3c27e3b848f4c879f500421ca5c"},
"eblurhash": {:hex, :eblurhash, "1.2.0", "ff461979542fcb1bfd428aaba6ee56e544975f6d657aa3dfcf3e314b1d1c2517", [:rebar3], [], "hexpm", "8fa6b740f1630adc0a3e425dbbb4ff92d036e62eb973e7a06676226137a10aa7"},
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "2.0.1", "2177c1c253f6dd3efd4b56d1cb76104d0a6ef044c6b9a7a0ad6d32665c4111e5", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "a3cc73211f2e75b89a03332183812ebe1ac08be2e25a1df5aa3d1422f92c45c3"},
@ -37,7 +37,7 @@
"erlsom": {:hex, :erlsom, "1.5.0", "c5a5cdd0ee0e8dca62bcc4b13ff08da24fdefc16ccd8b25282a2fda2ba1be24a", [:rebar3], [], "hexpm", "55a9dbf9cfa77fcfc108bd8e2c4f9f784dea228a8f4b06ea10b684944946955a"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [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 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"},
"ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.15.0", "8e43d49d8fe6b51cb16f0803e6f2a3f94081f51ac26cbf775a0745540dc2f16a", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.19", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.7", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2dae79a776c8680dd8b74046855ca0f3c9d4da28561407d86101fd84a0d8ce07"},
"ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.15.1", "8d049f56ad87114b0bd0c6f8d0f4bdaa91d688181e256260af61aa9f13c527af", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.19", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.7", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d4ac12a9fd366d51252662b8477a9eb01ccbb77362115ae6dfa0e253ab139de6"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.11.1", "a6e56209d6f98082cd197aa424333e7a0e38e79253fce9589117719728de4fef", [:mix], [{:ex_cldr, "~> 2.23", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "99e8eb3f48a30127bb11ab70f484c124c9fe5b11bce710c94c53939032b0c58c"},
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.8.0", "36495988148f1dc4aae1c2ef193dcb524f77008818e986f09850cf693e2f4dd3", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.15", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.19", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "673cc60ea7f163436758726c0c38f01587d856e98e5df42b1a8502aa32e8935e"},
"ex_cldr_languages": {:hex, :ex_cldr_languages, "0.2.2", "d7dab93272443b70e18e6aef0f62974418baaca3a3b31a66d51921ec1547113c", [:mix], [{:ex_cldr, "~> 2.2 and >= 2.2.1", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "d9cbf4bf643365b0042e774520ddfcbc31618efd5a5383fac98f75149961622c"},
@ -77,7 +77,7 @@
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"ip_reserved": {:hex, :ip_reserved, "0.1.0", "5c3b6df25eb875618e489db47e00fb8dac53bc2b0dc2d546b713e6141210fe9f", [:mix], [{:inet_cidr, "~> 1.0.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}], "hexpm", "88b0e96f40048f214b9e90e64eaebbf18acfec066008d7ef993b08282b2fe484"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
"jose": {:hex, :jose, "1.11.2", "f4c018ccf4fdce22c71e44d471f15f723cb3efab5d909ab2ba202b5bf35557b3", [:mix, :rebar3], [], "hexpm", "98143fbc48d55f3a18daba82d34fe48959d44538e9697c08f34200fa5f0947d2"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"junit_formatter": {:hex, :junit_formatter, "3.3.0", "bd7914d92885f7cf949dbe1dc6bacf76badfb2c1f5f7b3f9433c20e5b6ec42c8", [:mix], [], "hexpm", "4d040410925324b155ae4c7d41e884a0cdebe53b917bee4f22adf152e987a666"},
@ -101,7 +101,7 @@
"oauther": {:hex, :oauther, "1.1.1", "7d8b16167bb587ecbcddd3f8792beb9ec3e7b65c1f8ebd86b8dd25318d535752", [:mix], [], "hexpm", "9374f4302045321874cccdc57eb975893643bd69c3b22bf1312dab5f06e5788e"},
"oban": {:hex, :oban, "2.8.0", "e44b19a30e30bb983099f55d59749316ff0eaf5dfef4214e1190738176653e50", [:mix], [{:ecto_sql, ">= 3.4.3", [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", "2954a2ac418f7cc4217c0772a3dd3a70e2966240583b97f4126a489e1300a573"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"},
"phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.3.0", "2c69a452c2e0ee8c93345ae1cdc1696ef4877ff9cbb15c305def41960c3c4ebf", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0ac491924217550c8f42c81c1f390b5d81517d12ceaf9abf3e701156760a848e"},
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [: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", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},