feat(events): 1394 Long events, recurring events --> activities
This commit is contained in:
commit
72d78ed8f4
|
@ -36,6 +36,7 @@ config :mobilizon, :instance,
|
||||||
unconfirmed_user_grace_period_hours: 48,
|
unconfirmed_user_grace_period_hours: 48,
|
||||||
activity_expire_days: 365,
|
activity_expire_days: 365,
|
||||||
activity_keep_number: 100,
|
activity_keep_number: 100,
|
||||||
|
duration_of_long_event: 0,
|
||||||
enable_instance_feeds: true,
|
enable_instance_feeds: true,
|
||||||
email_from: "noreply@localhost",
|
email_from: "noreply@localhost",
|
||||||
email_reply_to: "noreply@localhost"
|
email_reply_to: "noreply@localhost"
|
||||||
|
|
|
@ -2,7 +2,8 @@ import Config
|
||||||
|
|
||||||
config :mobilizon, :instance,
|
config :mobilizon, :instance,
|
||||||
name: "Test instance",
|
name: "Test instance",
|
||||||
registrations_open: true
|
registrations_open: true,
|
||||||
|
duration_of_long_event: 0
|
||||||
|
|
||||||
# We don't run a server during test. If one is required,
|
# We don't run a server during test. If one is required,
|
||||||
# you can enable the server option below.
|
# you can enable the server option below.
|
||||||
|
|
|
@ -94,6 +94,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
|
||||||
registrations_allowlist: Config.instance_registrations_allowlist?(),
|
registrations_allowlist: Config.instance_registrations_allowlist?(),
|
||||||
contact: Config.contact(),
|
contact: Config.contact(),
|
||||||
demo_mode: Config.instance_demo_mode?(),
|
demo_mode: Config.instance_demo_mode?(),
|
||||||
|
long_events: Config.instance_long_events?(),
|
||||||
description: Config.instance_description(),
|
description: Config.instance_description(),
|
||||||
long_description: Config.instance_long_description(),
|
long_description: Config.instance_long_description(),
|
||||||
slogan: Config.instance_slogan(),
|
slogan: Config.instance_slogan(),
|
||||||
|
|
|
@ -31,6 +31,7 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
|
||||||
)
|
)
|
||||||
|
|
||||||
field(:demo_mode, :boolean, description: "Whether the demo mode is enabled")
|
field(:demo_mode, :boolean, description: "Whether the demo mode is enabled")
|
||||||
|
field(:long_events, :boolean, description: "Whether the long events mode is enabled")
|
||||||
field(:country_code, :string, description: "The country code from the IP")
|
field(:country_code, :string, description: "The country code from the IP")
|
||||||
field(:location, :lonlat, description: "The IP's location")
|
field(:location, :lonlat, description: "The IP's location")
|
||||||
field(:geocoding, :geocoding, description: "The instance's geocoding settings")
|
field(:geocoding, :geocoding, description: "The instance's geocoding settings")
|
||||||
|
|
|
@ -273,6 +273,8 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||||
description: "Radius around the location to search in"
|
description: "Radius around the location to search in"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
arg(:longevents, :boolean, description: "if mention filter in or out long events")
|
||||||
|
|
||||||
arg(:bbox, :string, description: "The bbox to search events into")
|
arg(:bbox, :string, description: "The bbox to search events into")
|
||||||
arg(:zoom, :integer, description: "The zoom level for searching events")
|
arg(:zoom, :integer, description: "The zoom level for searching events")
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,9 @@ defmodule Mobilizon.Config do
|
||||||
@spec instance_demo_mode? :: boolean
|
@spec instance_demo_mode? :: boolean
|
||||||
def instance_demo_mode?, do: to_boolean(instance_config()[:demo])
|
def instance_demo_mode?, do: to_boolean(instance_config()[:demo])
|
||||||
|
|
||||||
|
@spec instance_long_events? :: boolean
|
||||||
|
def instance_long_events?, do: instance_config()[:duration_of_long_event] > 0
|
||||||
|
|
||||||
@spec instance_repository :: String.t()
|
@spec instance_repository :: String.t()
|
||||||
def instance_repository, do: instance_config()[:repository]
|
def instance_repository, do: instance_config()[:repository]
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule Mobilizon.Events do
|
||||||
|
|
||||||
alias Mobilizon.Actors.{Actor, Follower}
|
alias Mobilizon.Actors.{Actor, Follower}
|
||||||
alias Mobilizon.Addresses.Address
|
alias Mobilizon.Addresses.Address
|
||||||
|
alias Mobilizon.Config
|
||||||
|
|
||||||
alias Mobilizon.Events.{
|
alias Mobilizon.Events.{
|
||||||
Event,
|
Event,
|
||||||
|
@ -571,6 +572,7 @@ defmodule Mobilizon.Events do
|
||||||
|> events_for_search_query()
|
|> events_for_search_query()
|
||||||
|> events_for_begins_on(Map.get(args, :begins_on, DateTime.utc_now()))
|
|> events_for_begins_on(Map.get(args, :begins_on, DateTime.utc_now()))
|
||||||
|> events_for_ends_on(Map.get(args, :ends_on))
|
|> events_for_ends_on(Map.get(args, :ends_on))
|
||||||
|
|> events_for_longevents(args)
|
||||||
|> events_for_category(args)
|
|> events_for_category(args)
|
||||||
|> events_for_categories(args)
|
|> events_for_categories(args)
|
||||||
|> events_for_languages(args)
|
|> events_for_languages(args)
|
||||||
|
@ -1377,6 +1379,38 @@ defmodule Mobilizon.Events do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec events_for_longevents(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||||
|
defp events_for_longevents(query, args) do
|
||||||
|
duration = Config.get([:instance, :duration_of_long_event], 0)
|
||||||
|
|
||||||
|
if duration <= 0 do
|
||||||
|
query
|
||||||
|
else
|
||||||
|
longevents = Map.get(args, :longevents)
|
||||||
|
|
||||||
|
case longevents do
|
||||||
|
nil ->
|
||||||
|
query
|
||||||
|
|
||||||
|
true ->
|
||||||
|
where(
|
||||||
|
query,
|
||||||
|
[q],
|
||||||
|
not is_nil(q.ends_on) and
|
||||||
|
q.ends_on > fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
|
||||||
|
)
|
||||||
|
|
||||||
|
false ->
|
||||||
|
where(
|
||||||
|
query,
|
||||||
|
[q],
|
||||||
|
is_nil(q.ends_on) or
|
||||||
|
q.ends_on <= fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
@spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||||
defp events_for_category(query, %{category: category}) when is_valid_string(category) do
|
defp events_for_category(query, %{category: category}) when is_valid_string(category) do
|
||||||
where(query, [q], q.category == ^category)
|
where(query, [q], q.category == ^category)
|
||||||
|
|
|
@ -187,6 +187,9 @@ type Config {
|
||||||
"Whether the demo mode is enabled"
|
"Whether the demo mode is enabled"
|
||||||
demoMode: Boolean
|
demoMode: Boolean
|
||||||
|
|
||||||
|
"Whether the long events mode is enabled"
|
||||||
|
longEvents: Boolean
|
||||||
|
|
||||||
"The country code from the IP"
|
"The country code from the IP"
|
||||||
countryCode: String
|
countryCode: String
|
||||||
|
|
||||||
|
@ -2242,6 +2245,9 @@ type RootQueryType {
|
||||||
|
|
||||||
"Filter events by their end date"
|
"Filter events by their end date"
|
||||||
endsOn: DateTime
|
endsOn: DateTime
|
||||||
|
|
||||||
|
"Filter for long events in function of configuration parameter 'duration_of_long_event'"
|
||||||
|
longevents: Boolean
|
||||||
): Events
|
): Events
|
||||||
|
|
||||||
"Interact with an URI"
|
"Interact with an URI"
|
||||||
|
|
|
@ -12,6 +12,31 @@
|
||||||
class="rounded-lg"
|
class="rounded-lg"
|
||||||
:class="{ 'sm:w-full sm:max-w-[20rem]': mode === 'row' }"
|
:class="{ 'sm:w-full sm:max-w-[20rem]': mode === 'row' }"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
class="-mt-3 h-0 mb-3 ltr:ml-0 rtl:mr-0 block relative z-10"
|
||||||
|
:class="{
|
||||||
|
'sm:hidden': mode === 'row',
|
||||||
|
'calendar-simple': !isDifferentBeginsEndsDate,
|
||||||
|
'calendar-double': isDifferentBeginsEndsDate,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<date-calendar-icon
|
||||||
|
:small="true"
|
||||||
|
v-if="!mergedOptions.hideDate"
|
||||||
|
:date="event.beginsOn.toString()"
|
||||||
|
/>
|
||||||
|
<MenuDown
|
||||||
|
:small="true"
|
||||||
|
class="left-3 relative"
|
||||||
|
v-if="!mergedOptions.hideDate && isDifferentBeginsEndsDate"
|
||||||
|
/>
|
||||||
|
<date-calendar-icon
|
||||||
|
:small="true"
|
||||||
|
v-if="!mergedOptions.hideDate && isDifferentBeginsEndsDate"
|
||||||
|
:date="event.endsOn?.toString()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<figure class="block relative pt-40">
|
<figure class="block relative pt-40">
|
||||||
<lazy-image-wrapper
|
<lazy-image-wrapper
|
||||||
:picture="event.picture"
|
:picture="event.picture"
|
||||||
|
@ -48,21 +73,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 flex-auto" :class="{ 'sm:flex-1': mode === 'row' }">
|
<div class="p-2 flex-auto" :class="{ 'sm:flex-1': mode === 'row' }">
|
||||||
<div class="relative flex flex-col h-full">
|
<div class="relative flex flex-col h-full">
|
||||||
<div
|
|
||||||
class="-mt-3 h-0 flex mb-3 ltr:ml-0 rtl:mr-0 items-end self-start"
|
|
||||||
:class="{ 'sm:hidden': mode === 'row' }"
|
|
||||||
>
|
|
||||||
<date-calendar-icon
|
|
||||||
:small="true"
|
|
||||||
v-if="!mergedOptions.hideDate"
|
|
||||||
:date="event.beginsOn.toString()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span
|
<span
|
||||||
class="text-gray-700 dark:text-white font-semibold hidden"
|
class="text-gray-700 dark:text-white font-semibold hidden"
|
||||||
:class="{ 'sm:block': mode === 'row' }"
|
:class="{ 'sm:block': mode === 'row' }"
|
||||||
|
v-if="!isDifferentBeginsEndsDate"
|
||||||
>{{ formatDateTimeWithCurrentLocale }}</span
|
>{{ formatDateTimeWithCurrentLocale }}</span
|
||||||
>
|
>
|
||||||
|
<span
|
||||||
|
class="text-gray-700 dark:text-white font-semibold hidden"
|
||||||
|
:class="{ 'sm:block': mode === 'row' }"
|
||||||
|
v-if="isDifferentBeginsEndsDate"
|
||||||
|
>{{ formatBeginsOnDateWithCurrentLocale }}
|
||||||
|
<ArrowRightThin :small="true" style="display: ruby" />
|
||||||
|
{{ formatEndsOnDateWithCurrentLocale }}</span
|
||||||
|
>
|
||||||
<div class="w-full flex flex-col justify-between h-full">
|
<div class="w-full flex flex-col justify-between h-full">
|
||||||
<h2
|
<h2
|
||||||
class="mt-0 mb-2 text-2xl line-clamp-3 font-bold text-violet-3 dark:text-white"
|
class="mt-0 mb-2 text-2xl line-clamp-3 font-bold text-violet-3 dark:text-white"
|
||||||
|
@ -152,6 +176,16 @@
|
||||||
</div>
|
</div>
|
||||||
</LinkOrRouterLink>
|
</LinkOrRouterLink>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
.calendar-simple {
|
||||||
|
bottom: -117px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
.calendar-double {
|
||||||
|
bottom: -45px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
|
@ -161,6 +195,8 @@ import {
|
||||||
organizerAvatarUrl,
|
organizerAvatarUrl,
|
||||||
} from "@/types/event.model";
|
} from "@/types/event.model";
|
||||||
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
||||||
|
import ArrowRightThin from "vue-material-design-icons/ArrowRightThin.vue";
|
||||||
|
import MenuDown from "vue-material-design-icons/MenuDown.vue";
|
||||||
import LazyImageWrapper from "@/components/Image/LazyImageWrapper.vue";
|
import LazyImageWrapper from "@/components/Image/LazyImageWrapper.vue";
|
||||||
import { EventStatus } from "@/types/enums";
|
import { EventStatus } from "@/types/enums";
|
||||||
import RouteName from "../../router/name";
|
import RouteName from "../../router/name";
|
||||||
|
@ -170,7 +206,7 @@ import { computed, inject } from "vue";
|
||||||
import MobilizonTag from "@/components/TagElement.vue";
|
import MobilizonTag from "@/components/TagElement.vue";
|
||||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||||
import Video from "vue-material-design-icons/Video.vue";
|
import Video from "vue-material-design-icons/Video.vue";
|
||||||
import { formatDateTimeForEvent } from "@/utils/datetime";
|
import { formatDateForEvent, formatDateTimeForEvent } from "@/utils/datetime";
|
||||||
import type { Locale } from "date-fns";
|
import type { Locale } from "date-fns";
|
||||||
import LinkOrRouterLink from "../core/LinkOrRouterLink.vue";
|
import LinkOrRouterLink from "../core/LinkOrRouterLink.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
@ -212,6 +248,28 @@ const actorAvatarURL = computed<string | null>(() =>
|
||||||
|
|
||||||
const dateFnsLocale = inject<Locale>("dateFnsLocale");
|
const dateFnsLocale = inject<Locale>("dateFnsLocale");
|
||||||
|
|
||||||
|
const isDifferentBeginsEndsDate = computed(() => {
|
||||||
|
if (!dateFnsLocale) return;
|
||||||
|
const beginsOnStr = formatDateForEvent(
|
||||||
|
new Date(props.event.beginsOn),
|
||||||
|
dateFnsLocale
|
||||||
|
);
|
||||||
|
const endsOnStr = props.event.endsOn
|
||||||
|
? formatDateForEvent(new Date(props.event.endsOn), dateFnsLocale)
|
||||||
|
: null;
|
||||||
|
return endsOnStr && endsOnStr != beginsOnStr;
|
||||||
|
});
|
||||||
|
|
||||||
|
const formatBeginsOnDateWithCurrentLocale = computed(() => {
|
||||||
|
if (!dateFnsLocale) return;
|
||||||
|
return formatDateForEvent(new Date(props.event.beginsOn), dateFnsLocale);
|
||||||
|
});
|
||||||
|
|
||||||
|
const formatEndsOnDateWithCurrentLocale = computed(() => {
|
||||||
|
if (!dateFnsLocale) return;
|
||||||
|
return formatDateForEvent(new Date(props.event.endsOn), dateFnsLocale);
|
||||||
|
});
|
||||||
|
|
||||||
const formatDateTimeWithCurrentLocale = computed(() => {
|
const formatDateTimeWithCurrentLocale = computed(() => {
|
||||||
if (!dateFnsLocale) return;
|
if (!dateFnsLocale) return;
|
||||||
return formatDateTimeForEvent(new Date(props.event.beginsOn), dateFnsLocale);
|
return formatDateTimeForEvent(new Date(props.event.beginsOn), dateFnsLocale);
|
||||||
|
|
|
@ -173,6 +173,8 @@ const icons: Record<string, () => Promise<any>> = {
|
||||||
import(
|
import(
|
||||||
`../../../node_modules/vue-material-design-icons/CalendarRemove.vue`
|
`../../../node_modules/vue-material-design-icons/CalendarRemove.vue`
|
||||||
),
|
),
|
||||||
|
CalendarStar: () =>
|
||||||
|
import(`../../../node_modules/vue-material-design-icons/CalendarStar.vue`),
|
||||||
FileDocumentEdit: () =>
|
FileDocumentEdit: () =>
|
||||||
import(
|
import(
|
||||||
`../../../node_modules/vue-material-design-icons/FileDocumentEdit.vue`
|
`../../../node_modules/vue-material-design-icons/FileDocumentEdit.vue`
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
ANONYMOUS_PARTICIPATION_CONFIG,
|
ANONYMOUS_PARTICIPATION_CONFIG,
|
||||||
ANONYMOUS_REPORTS_CONFIG,
|
ANONYMOUS_REPORTS_CONFIG,
|
||||||
DEMO_MODE,
|
DEMO_MODE,
|
||||||
|
LONG_EVENTS,
|
||||||
EVENT_CATEGORIES,
|
EVENT_CATEGORIES,
|
||||||
EVENT_PARTICIPANTS,
|
EVENT_PARTICIPANTS,
|
||||||
FEATURES,
|
FEATURES,
|
||||||
|
@ -188,6 +189,15 @@ export function useIsDemoMode() {
|
||||||
return { isDemoMode, error, loading };
|
return { isDemoMode, error, loading };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useIsLongEvents() {
|
||||||
|
const { result, error, loading } = useQuery<{
|
||||||
|
config: Pick<IConfig, "longEvents">;
|
||||||
|
}>(LONG_EVENTS);
|
||||||
|
|
||||||
|
const islongEvents = computed(() => result.value?.config.longEvents);
|
||||||
|
return { islongEvents, error, loading };
|
||||||
|
}
|
||||||
|
|
||||||
export function useAnalytics() {
|
export function useAnalytics() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "analytics">;
|
config: Pick<IConfig, "analytics">;
|
||||||
|
|
|
@ -10,6 +10,7 @@ export const CONFIG = gql`
|
||||||
registrationsOpen
|
registrationsOpen
|
||||||
registrationsAllowlist
|
registrationsAllowlist
|
||||||
demoMode
|
demoMode
|
||||||
|
longEvents
|
||||||
countryCode
|
countryCode
|
||||||
languages
|
languages
|
||||||
eventCategories {
|
eventCategories {
|
||||||
|
@ -425,6 +426,14 @@ export const DEMO_MODE = gql`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const LONG_EVENTS = gql`
|
||||||
|
query LongEvents {
|
||||||
|
config {
|
||||||
|
longEvents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const ANALYTICS = gql`
|
export const ANALYTICS = gql`
|
||||||
query Analytics {
|
query Analytics {
|
||||||
config {
|
config {
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||||
$searchTarget: SearchTarget
|
$searchTarget: SearchTarget
|
||||||
$beginsOn: DateTime
|
$beginsOn: DateTime
|
||||||
$endsOn: DateTime
|
$endsOn: DateTime
|
||||||
|
$longevents: Boolean
|
||||||
$bbox: String
|
$bbox: String
|
||||||
$zoom: Int
|
$zoom: Int
|
||||||
$eventPage: Int
|
$eventPage: Int
|
||||||
|
@ -54,6 +55,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||||
searchTarget: $searchTarget
|
searchTarget: $searchTarget
|
||||||
beginsOn: $beginsOn
|
beginsOn: $beginsOn
|
||||||
endsOn: $endsOn
|
endsOn: $endsOn
|
||||||
|
longevents: $longevents
|
||||||
bbox: $bbox
|
bbox: $bbox
|
||||||
zoom: $zoom
|
zoom: $zoom
|
||||||
page: $eventPage
|
page: $eventPage
|
||||||
|
@ -67,6 +69,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||||
title
|
title
|
||||||
uuid
|
uuid
|
||||||
beginsOn
|
beginsOn
|
||||||
|
endsOn
|
||||||
picture {
|
picture {
|
||||||
id
|
id
|
||||||
url
|
url
|
||||||
|
@ -152,6 +155,7 @@ export const SEARCH_EVENTS = gql`
|
||||||
$endsOn: DateTime
|
$endsOn: DateTime
|
||||||
$eventPage: Int
|
$eventPage: Int
|
||||||
$limit: Int
|
$limit: Int
|
||||||
|
$longevents: Boolean
|
||||||
) {
|
) {
|
||||||
searchEvents(
|
searchEvents(
|
||||||
location: $location
|
location: $location
|
||||||
|
@ -164,6 +168,7 @@ export const SEARCH_EVENTS = gql`
|
||||||
endsOn: $endsOn
|
endsOn: $endsOn
|
||||||
page: $eventPage
|
page: $eventPage
|
||||||
limit: $limit
|
limit: $limit
|
||||||
|
longevents: $longevents
|
||||||
) {
|
) {
|
||||||
total
|
total
|
||||||
elements {
|
elements {
|
||||||
|
|
|
@ -204,6 +204,7 @@
|
||||||
"No events found": "No events found",
|
"No events found": "No events found",
|
||||||
"No group found": "No group found",
|
"No group found": "No group found",
|
||||||
"No groups found": "No groups found",
|
"No groups found": "No groups found",
|
||||||
|
"No activities found": "No activities found",
|
||||||
"No instance follows your instance yet.": "No instance follows your instance yet.",
|
"No instance follows your instance yet.": "No instance follows your instance yet.",
|
||||||
"No instance to approve|Approve instance|Approve {number} instances": "No instance to approve|Approve instance|Approve {number} instances",
|
"No instance to approve|Approve instance|Approve {number} instances": "No instance to approve|Approve instance|Approve {number} instances",
|
||||||
"No instance to reject|Reject instance|Reject {number} instances": "No instance to reject|Reject instance|Reject {number} instances",
|
"No instance to reject|Reject instance|Reject {number} instances": "No instance to reject|Reject instance|Reject {number} instances",
|
||||||
|
@ -1394,6 +1395,7 @@
|
||||||
"Reported content": "Reported content",
|
"Reported content": "Reported content",
|
||||||
"No results found": "No results found",
|
"No results found": "No results found",
|
||||||
"{eventsCount} events found": "No events found|One event found|{eventsCount} events found",
|
"{eventsCount} events found": "No events found|One event found|{eventsCount} events found",
|
||||||
|
"{eventsCount} activities found": "No activities found|One activity found|{eventsCount} activities found",
|
||||||
"{groupsCount} groups found": "No groups found|One group found|{groupsCount} groups found",
|
"{groupsCount} groups found": "No groups found|One group found|{groupsCount} groups found",
|
||||||
"{resultsCount} results found": "No results found|On result found|{resultsCount} results found",
|
"{resultsCount} results found": "No results found|On result found|{resultsCount} results found",
|
||||||
"Loading map": "Loading map",
|
"Loading map": "Loading map",
|
||||||
|
|
|
@ -716,6 +716,7 @@
|
||||||
"No end date": "Pas de date de fin",
|
"No end date": "Pas de date de fin",
|
||||||
"No event found at this address": "Aucun événement trouvé à cette addresse",
|
"No event found at this address": "Aucun événement trouvé à cette addresse",
|
||||||
"No events found": "Aucun événement trouvé",
|
"No events found": "Aucun événement trouvé",
|
||||||
|
"No activities found": "Aucun activité trouvé",
|
||||||
"No events found for {search}": "Aucun événement trouvé pour {search}",
|
"No events found for {search}": "Aucun événement trouvé pour {search}",
|
||||||
"No follower matches the filters": "Aucun·e abonné·e ne correspond aux filtres",
|
"No follower matches the filters": "Aucun·e abonné·e ne correspond aux filtres",
|
||||||
"No group found": "Aucun groupe trouvé",
|
"No group found": "Aucun groupe trouvé",
|
||||||
|
@ -1544,6 +1545,7 @@
|
||||||
"{count} participants": "Aucun·e participant·e | Un·e participant·e | {count} participant·e·s",
|
"{count} participants": "Aucun·e participant·e | Un·e participant·e | {count} participant·e·s",
|
||||||
"{count} requests waiting": "Une demande en attente|{count} demandes en attente",
|
"{count} requests waiting": "Une demande en attente|{count} demandes en attente",
|
||||||
"{eventsCount} events found": "Aucun événement trouvé|Un événement trouvé|{eventsCount} événements trouvés",
|
"{eventsCount} events found": "Aucun événement trouvé|Un événement trouvé|{eventsCount} événements trouvés",
|
||||||
|
"{eventsCount} activities found": "Aucune activité trouvé|Une activité trouvé|{eventsCount} activités trouvés",
|
||||||
"{folder} - Resources": "{folder} - Ressources",
|
"{folder} - Resources": "{folder} - Ressources",
|
||||||
"{groupsCount} groups found": "Aucun groupe trouvé|Un groupe trouvé|{groupsCount} groupes trouvés",
|
"{groupsCount} groups found": "Aucun groupe trouvé|Un groupe trouvé|{groupsCount} groupes trouvés",
|
||||||
"{group} activity timeline": "Timeline de l'activité de {group}",
|
"{group} activity timeline": "Timeline de l'activité de {group}",
|
||||||
|
|
|
@ -41,6 +41,7 @@ export interface IConfig {
|
||||||
registrationsOpen: boolean;
|
registrationsOpen: boolean;
|
||||||
registrationsAllowlist: boolean;
|
registrationsAllowlist: boolean;
|
||||||
demoMode: boolean;
|
demoMode: boolean;
|
||||||
|
longEvents: boolean;
|
||||||
countryCode: string;
|
countryCode: string;
|
||||||
eventCategories: { id: string; label: string }[];
|
eventCategories: { id: string; label: string }[];
|
||||||
languages: string[];
|
languages: string[];
|
||||||
|
|
|
@ -134,6 +134,8 @@ export enum SearchTabs {
|
||||||
export enum ContentType {
|
export enum ContentType {
|
||||||
ALL = "ALL",
|
ALL = "ALL",
|
||||||
EVENTS = "EVENTS",
|
EVENTS = "EVENTS",
|
||||||
|
SHORTEVENTS = "SHORTEVENTS",
|
||||||
|
LONGEVENTS = "LONGEVENTS",
|
||||||
GROUPS = "GROUPS",
|
GROUPS = "GROUPS",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,10 +69,15 @@ function formatDateTimeForEvent(dateTime: Date, locale: Locale): string {
|
||||||
return format(dateTime, "PPp", { locale });
|
return format(dateTime, "PPp", { locale });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDateForEvent(dateTime: Date, locale: Locale): string {
|
||||||
|
return format(dateTime, "PP", { locale });
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
localeMonthNames,
|
localeMonthNames,
|
||||||
localeShortWeekDayNames,
|
localeShortWeekDayNames,
|
||||||
formatBytes,
|
formatBytes,
|
||||||
roundToNearestMinute,
|
roundToNearestMinute,
|
||||||
formatDateTimeForEvent,
|
formatDateTimeForEvent,
|
||||||
|
formatDateForEvent,
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,6 +45,16 @@
|
||||||
:size="24"
|
:size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Calendar
|
||||||
|
v-if="content.contentType === ContentType.SHORTEVENTS"
|
||||||
|
:size="24"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CalendarStar
|
||||||
|
v-if="content.contentType === ContentType.LONGEVENTS"
|
||||||
|
:size="24"
|
||||||
|
/>
|
||||||
|
|
||||||
<AccountMultiple
|
<AccountMultiple
|
||||||
v-if="content.contentType === ContentType.GROUPS"
|
v-if="content.contentType === ContentType.GROUPS"
|
||||||
:size="24"
|
:size="24"
|
||||||
|
@ -443,8 +453,15 @@
|
||||||
class="hidden sm:flex items-center justify-between dark:text-slate-100 mb-2"
|
class="hidden sm:flex items-center justify-between dark:text-slate-100 mb-2"
|
||||||
>
|
>
|
||||||
<p v-if="totalCount === 0">
|
<p v-if="totalCount === 0">
|
||||||
<span v-if="contentType === ContentType.EVENTS">{{
|
<span
|
||||||
t("No events found")
|
v-if="
|
||||||
|
contentType === ContentType.EVENTS ||
|
||||||
|
contentType === ContentType.SHORTEVENTS
|
||||||
|
"
|
||||||
|
>{{ t("No events found") }}</span
|
||||||
|
>
|
||||||
|
<span v-else-if="contentType === ContentType.LONGEVENTS">{{
|
||||||
|
t("No activities found")
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-else-if="contentType === ContentType.GROUPS">{{
|
<span v-else-if="contentType === ContentType.GROUPS">{{
|
||||||
t("No groups found")
|
t("No groups found")
|
||||||
|
@ -452,7 +469,12 @@
|
||||||
<span v-else>{{ t("No results found") }}</span>
|
<span v-else>{{ t("No results found") }}</span>
|
||||||
</p>
|
</p>
|
||||||
<p v-else>
|
<p v-else>
|
||||||
<span v-if="contentType === 'EVENTS'">
|
<span
|
||||||
|
v-if="
|
||||||
|
contentType === ContentType.EVENTS ||
|
||||||
|
contentType === ContentType.SHORTEVENTS
|
||||||
|
"
|
||||||
|
>
|
||||||
{{
|
{{
|
||||||
t(
|
t(
|
||||||
"{eventsCount} events found",
|
"{eventsCount} events found",
|
||||||
|
@ -461,7 +483,16 @@
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="contentType === 'GROUPS'">
|
<span v-else-if="contentType === ContentType.LONGEVENTS">
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"{eventsCount} activities found",
|
||||||
|
{ eventsCount: searchEvents?.total },
|
||||||
|
searchEvents?.total ?? 0
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<span v-else-if="contentType === ContentType.GROUPS">
|
||||||
{{
|
{{
|
||||||
t(
|
t(
|
||||||
"{groupsCount} groups found",
|
"{groupsCount} groups found",
|
||||||
|
@ -597,7 +628,13 @@
|
||||||
:aria-current-label="t('Current page')"
|
:aria-current-label="t('Current page')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="contentType === ContentType.EVENTS">
|
<template
|
||||||
|
v-else-if="
|
||||||
|
contentType === ContentType.EVENTS ||
|
||||||
|
contentType === ContentType.SHORTEVENTS ||
|
||||||
|
contentType === ContentType.LONGEVENTS
|
||||||
|
"
|
||||||
|
>
|
||||||
<template v-if="searchLoading">
|
<template v-if="searchLoading">
|
||||||
<SkeletonEventResultList v-for="i in 8" :key="i" />
|
<SkeletonEventResultList v-for="i in 8" :key="i" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -625,13 +662,23 @@
|
||||||
>
|
>
|
||||||
</o-pagination>
|
</o-pagination>
|
||||||
</template>
|
</template>
|
||||||
<EmptyContent v-else-if="searchLoading === false" icon="calendar">
|
<EmptyContent
|
||||||
|
v-else-if="searchLoading === false"
|
||||||
|
:icon="
|
||||||
|
contentType === ContentType.LONGEVENTS
|
||||||
|
? 'calendar-star'
|
||||||
|
: 'calendar'
|
||||||
|
"
|
||||||
|
>
|
||||||
<span v-if="searchIsUrl">
|
<span v-if="searchIsUrl">
|
||||||
{{ t("No event found at this address") }}
|
{{ t("No event found at this address") }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="!search">
|
<span v-else-if="!search && contentType !== ContentType.LONGEVENTS">
|
||||||
{{ t("No events found") }}
|
{{ t("No events found") }}
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else-if="!search && contentType === ContentType.LONGEVENTS">
|
||||||
|
{{ t("No activities found") }}
|
||||||
|
</span>
|
||||||
<i18n-t keypath="No events found for {search}" tag="span" v-else>
|
<i18n-t keypath="No events found for {search}" tag="span" v-else>
|
||||||
<template #search>
|
<template #search>
|
||||||
<b>{{ search }}</b>
|
<b>{{ search }}</b>
|
||||||
|
@ -694,7 +741,7 @@
|
||||||
icon="account-multiple"
|
icon="account-multiple"
|
||||||
>
|
>
|
||||||
<span v-if="!search">
|
<span v-if="!search">
|
||||||
{{ t("No events found") }}
|
{{ t("No groups found") }}
|
||||||
</span>
|
</span>
|
||||||
<i18n-t keypath="No groups found for {search}" tag="span" v-else>
|
<i18n-t keypath="No groups found for {search}" tag="span" v-else>
|
||||||
<template #search>
|
<template #search>
|
||||||
|
@ -767,6 +814,7 @@ import {
|
||||||
booleanTransformer,
|
booleanTransformer,
|
||||||
} from "vue-use-route-query";
|
} from "vue-use-route-query";
|
||||||
import Calendar from "vue-material-design-icons/Calendar.vue";
|
import Calendar from "vue-material-design-icons/Calendar.vue";
|
||||||
|
import CalendarStar from "vue-material-design-icons/CalendarStar.vue";
|
||||||
import AccountMultiple from "vue-material-design-icons/AccountMultiple.vue";
|
import AccountMultiple from "vue-material-design-icons/AccountMultiple.vue";
|
||||||
import Magnify from "vue-material-design-icons/Magnify.vue";
|
import Magnify from "vue-material-design-icons/Magnify.vue";
|
||||||
|
|
||||||
|
@ -778,6 +826,7 @@ import langs from "@/i18n/langs.json";
|
||||||
import {
|
import {
|
||||||
useEventCategories,
|
useEventCategories,
|
||||||
useFeatures,
|
useFeatures,
|
||||||
|
useIsLongEvents,
|
||||||
useSearchConfig,
|
useSearchConfig,
|
||||||
} from "@/composition/apollo/config";
|
} from "@/composition/apollo/config";
|
||||||
import { coordsToGeoHash } from "@/utils/location";
|
import { coordsToGeoHash } from "@/utils/location";
|
||||||
|
@ -904,6 +953,7 @@ const GROUP_PAGE_LIMIT = 16;
|
||||||
|
|
||||||
const { features } = useFeatures();
|
const { features } = useFeatures();
|
||||||
const { eventCategories } = useEventCategories();
|
const { eventCategories } = useEventCategories();
|
||||||
|
const { islongEvents } = useIsLongEvents();
|
||||||
|
|
||||||
const orderedCategories = computed(() => {
|
const orderedCategories = computed(() => {
|
||||||
if (!eventCategories.value) return [];
|
if (!eventCategories.value) return [];
|
||||||
|
@ -1017,20 +1067,41 @@ const searchIsUrl = computed((): boolean => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const contentTypeMapping = computed(() => {
|
const contentTypeMapping = computed(() => {
|
||||||
return [
|
if (islongEvents.value) {
|
||||||
{
|
return [
|
||||||
contentType: "ALL",
|
{
|
||||||
label: t("Everything"),
|
contentType: "ALL",
|
||||||
},
|
label: t("Everything"),
|
||||||
{
|
},
|
||||||
contentType: "EVENTS",
|
{
|
||||||
label: t("Events"),
|
contentType: "SHORTEVENTS",
|
||||||
},
|
label: t("Events"),
|
||||||
{
|
},
|
||||||
contentType: "GROUPS",
|
{
|
||||||
label: t("Groups"),
|
contentType: "LONGEVENTS",
|
||||||
},
|
label: t("Activities"),
|
||||||
];
|
},
|
||||||
|
{
|
||||||
|
contentType: "GROUPS",
|
||||||
|
label: t("Groups"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
contentType: "ALL",
|
||||||
|
label: t("Everything"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentType: "EVENTS",
|
||||||
|
label: t("Events"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentType: "GROUPS",
|
||||||
|
label: t("Groups"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const eventDistance = computed(() => {
|
const eventDistance = computed(() => {
|
||||||
|
@ -1138,6 +1209,16 @@ const geoHashLocation = computed(() =>
|
||||||
|
|
||||||
const radius = computed(() => Number.parseInt(distance.value.slice(0, -3)));
|
const radius = computed(() => Number.parseInt(distance.value.slice(0, -3)));
|
||||||
|
|
||||||
|
const longEvents = computed(() => {
|
||||||
|
if (contentType.value === ContentType.SHORTEVENTS) {
|
||||||
|
return false;
|
||||||
|
} else if (contentType.value === ContentType.LONGEVENTS) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const totalCount = computed(() => {
|
const totalCount = computed(() => {
|
||||||
return (searchEvents.value?.total ?? 0) + (searchGroups.value?.total ?? 0);
|
return (searchEvents.value?.total ?? 0) + (searchGroups.value?.total ?? 0);
|
||||||
});
|
});
|
||||||
|
@ -1150,7 +1231,11 @@ const sortOptions = computed(() => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (contentType.value == ContentType.EVENTS) {
|
if (
|
||||||
|
contentType.value === ContentType.EVENTS ||
|
||||||
|
contentType.value === ContentType.SHORTEVENTS ||
|
||||||
|
contentType.value === ContentType.LONGEVENTS
|
||||||
|
) {
|
||||||
options.push(
|
options.push(
|
||||||
{
|
{
|
||||||
key: SortValues.START_TIME_ASC,
|
key: SortValues.START_TIME_ASC,
|
||||||
|
@ -1171,7 +1256,7 @@ const sortOptions = computed(() => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType.value == ContentType.GROUPS) {
|
if (contentType.value === ContentType.GROUPS) {
|
||||||
options.push({
|
options.push({
|
||||||
key: SortValues.MEMBER_COUNT_DESC,
|
key: SortValues.MEMBER_COUNT_DESC,
|
||||||
label: t("Number of members"),
|
label: t("Number of members"),
|
||||||
|
@ -1282,6 +1367,12 @@ watch(
|
||||||
case ContentType.EVENTS:
|
case ContentType.EVENTS:
|
||||||
eventPage.value = 1;
|
eventPage.value = 1;
|
||||||
break;
|
break;
|
||||||
|
case ContentType.SHORTEVENTS:
|
||||||
|
eventPage.value = 1;
|
||||||
|
break;
|
||||||
|
case ContentType.LONGEVENTS:
|
||||||
|
eventPage.value = 1;
|
||||||
|
break;
|
||||||
case ContentType.GROUPS:
|
case ContentType.GROUPS:
|
||||||
groupPage.value = 1;
|
groupPage.value = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -1298,6 +1389,7 @@ const { result: searchElementsResult, loading: searchLoading } = useQuery<{
|
||||||
location: geoHashLocation.value,
|
location: geoHashLocation.value,
|
||||||
beginsOn: start.value,
|
beginsOn: start.value,
|
||||||
endsOn: end.value,
|
endsOn: end.value,
|
||||||
|
longevents: longEvents.value,
|
||||||
radius: geoHashLocation.value ? radius.value : undefined,
|
radius: geoHashLocation.value ? radius.value : undefined,
|
||||||
eventPage:
|
eventPage:
|
||||||
contentType.value === ContentType.ALL ? page.value : eventPage.value,
|
contentType.value === ContentType.ALL ? page.value : eventPage.value,
|
||||||
|
|
|
@ -2,13 +2,24 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
|
||||||
use Mobilizon.Web.ConnCase
|
use Mobilizon.Web.ConnCase
|
||||||
alias Mobilizon.Actors
|
alias Mobilizon.Actors
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.GraphQL.AbsintheHelpers
|
alias Mobilizon.GraphQL.AbsintheHelpers
|
||||||
|
|
||||||
describe "Resolver: Get config" do
|
describe "Resolver: Get config" do
|
||||||
test "get_config/3 returns the instance config", context do
|
test "get_config/3 returns the instance config", context do
|
||||||
Cachex.clear("full_config")
|
Cachex.clear("full_config")
|
||||||
Mobilizon.Config.clear_config_cache()
|
Mobilizon.Config.clear_config_cache()
|
||||||
|
Config.put([:instance, :name], "Test instance")
|
||||||
|
Config.put([:instance, :registrations_open], true)
|
||||||
|
Config.put([:instance, :demo], false)
|
||||||
|
Config.put([:instance, :duration_of_long_event], 0)
|
||||||
|
|
||||||
|
Config.put(
|
||||||
|
[:instance, :description],
|
||||||
|
"Change this to a proper description of your instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
Config.put([:instance, :federating], true)
|
||||||
|
|
||||||
query = """
|
query = """
|
||||||
{
|
{
|
||||||
|
@ -48,5 +59,99 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
|
||||||
{:ok, %Actor{id: actor_id}} = Actors.get_or_create_internal_actor("anonymous")
|
{:ok, %Actor{id: actor_id}} = Actors.get_or_create_internal_actor("anonymous")
|
||||||
assert res["data"]["config"]["anonymous"]["actor_id"] == to_string(actor_id)
|
assert res["data"]["config"]["anonymous"]["actor_id"] == to_string(actor_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "get_config/3 returns the instance config default", context do
|
||||||
|
Cachex.clear("full_config")
|
||||||
|
Mobilizon.Config.clear_config_cache()
|
||||||
|
Config.put([:instance, :name], "Test instance")
|
||||||
|
Config.put([:instance, :registrations_open], true)
|
||||||
|
Config.put([:instance, :demo], false)
|
||||||
|
Config.put([:instance, :duration_of_long_event], 0)
|
||||||
|
|
||||||
|
Config.put(
|
||||||
|
[:instance, :description],
|
||||||
|
"Change this to a proper description of your instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
Config.put([:instance, :federating], true)
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
config {
|
||||||
|
name,
|
||||||
|
registrationsOpen,
|
||||||
|
registrations_allowlist,
|
||||||
|
contact,
|
||||||
|
demo_mode,
|
||||||
|
long_events,
|
||||||
|
description,
|
||||||
|
long_description,
|
||||||
|
slogan,
|
||||||
|
languages,
|
||||||
|
timezones,
|
||||||
|
rules,
|
||||||
|
version,
|
||||||
|
federating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
context.conn
|
||||||
|
|> AbsintheHelpers.graphql_query(query: query)
|
||||||
|
|
||||||
|
assert res["data"]["config"]["name"] == "Test instance"
|
||||||
|
assert res["data"]["config"]["registrationsOpen"] == true
|
||||||
|
assert res["data"]["config"]["registrations_allowlist"] == false
|
||||||
|
assert res["data"]["config"]["contact"] == nil
|
||||||
|
assert res["data"]["config"]["demo_mode"] == false
|
||||||
|
assert res["data"]["config"]["long_events"] == false
|
||||||
|
|
||||||
|
assert res["data"]["config"]["description"] ==
|
||||||
|
"Change this to a proper description of your instance"
|
||||||
|
|
||||||
|
assert res["data"]["config"]["long_description"] == nil
|
||||||
|
assert res["data"]["config"]["slogan"] == nil
|
||||||
|
assert res["data"]["config"]["languages"] == []
|
||||||
|
assert length(res["data"]["config"]["timezones"]) == 596
|
||||||
|
assert res["data"]["config"]["rules"] == nil
|
||||||
|
assert String.slice(res["data"]["config"]["version"], 0, 5) == "4.0.2"
|
||||||
|
assert res["data"]["config"]["federating"] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_config/3 returns the instance config changed", context do
|
||||||
|
Cachex.clear("full_config")
|
||||||
|
Mobilizon.Config.clear_config_cache()
|
||||||
|
Config.put([:instance, :name], "My instance")
|
||||||
|
Config.put([:instance, :registrations_open], false)
|
||||||
|
Config.put([:instance, :demo], true)
|
||||||
|
Config.put([:instance, :duration_of_long_event], 30)
|
||||||
|
Config.put([:instance, :description], "My description")
|
||||||
|
Config.put([:instance, :federating], false)
|
||||||
|
|
||||||
|
query = """
|
||||||
|
{
|
||||||
|
config {
|
||||||
|
name,
|
||||||
|
registrationsOpen,
|
||||||
|
demo_mode,
|
||||||
|
long_events,
|
||||||
|
description,
|
||||||
|
federating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
res =
|
||||||
|
context.conn
|
||||||
|
|> AbsintheHelpers.graphql_query(query: query)
|
||||||
|
|
||||||
|
assert res["data"]["config"]["name"] == "My instance"
|
||||||
|
assert res["data"]["config"]["registrationsOpen"] == false
|
||||||
|
assert res["data"]["config"]["demo_mode"] == true
|
||||||
|
assert res["data"]["config"]["long_events"] == true
|
||||||
|
assert res["data"]["config"]["description"] == "My description"
|
||||||
|
assert res["data"]["config"]["federating"] == false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,11 +4,11 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
|
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Events.Event
|
alias Mobilizon.Events.Event
|
||||||
alias Mobilizon.Federation.ActivityPub.Relay
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
alias Mobilizon.Service.Workers
|
|
||||||
|
|
||||||
alias Mobilizon.GraphQL.AbsintheHelpers
|
alias Mobilizon.GraphQL.AbsintheHelpers
|
||||||
|
alias Mobilizon.Service.Workers
|
||||||
|
|
||||||
setup %{conn: conn} do
|
setup %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
@ -18,8 +18,8 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
|
|
||||||
describe "search events/3" do
|
describe "search events/3" do
|
||||||
@search_events_query """
|
@search_events_query """
|
||||||
query SearchEvents($location: String, $radius: Float, $tags: String, $term: String, $beginsOn: DateTime, $endsOn: DateTime, $searchTarget: SearchTarget) {
|
query SearchEvents($location: String, $radius: Float, $tags: String, $term: String, $beginsOn: DateTime, $endsOn: DateTime, $longevents:Boolean, $searchTarget: SearchTarget) {
|
||||||
searchEvents(location: $location, radius: $radius, tags: $tags, term: $term, beginsOn: $beginsOn, endsOn: $endsOn, searchTarget: $searchTarget) {
|
searchEvents(location: $location, radius: $radius, tags: $tags, term: $term, beginsOn: $beginsOn, endsOn: $endsOn, longevents: $longevents, searchTarget: $searchTarget) {
|
||||||
total,
|
total,
|
||||||
elements {
|
elements {
|
||||||
id
|
id
|
||||||
|
@ -149,6 +149,7 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "finds events by begins_on and ends_on", %{conn: conn} do
|
test "finds events by begins_on and ends_on", %{conn: conn} do
|
||||||
|
Config.put([:instance, :duration_of_long_event], 0)
|
||||||
now = DateTime.utc_now()
|
now = DateTime.utc_now()
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
@ -183,6 +184,214 @@ defmodule Mobilizon.GraphQL.Resolvers.SearchTest do
|
||||||
event.uuid
|
event.uuid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "finds 4 events : long event disabled", %{conn: conn} do
|
||||||
|
Config.put([:instance, :duration_of_long_event], 0)
|
||||||
|
now = DateTime.utc_now()
|
||||||
|
|
||||||
|
event1 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Cours 10j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 14)
|
||||||
|
)
|
||||||
|
|
||||||
|
event2 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 29j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 33)
|
||||||
|
)
|
||||||
|
|
||||||
|
event3 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 31j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 35)
|
||||||
|
)
|
||||||
|
|
||||||
|
event4 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 40j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 44)
|
||||||
|
)
|
||||||
|
|
||||||
|
Workers.BuildSearch.insert_search_event(event1)
|
||||||
|
Workers.BuildSearch.insert_search_event(event2)
|
||||||
|
Workers.BuildSearch.insert_search_event(event3)
|
||||||
|
Workers.BuildSearch.insert_search_event(event4)
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: false}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 4
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event1.uuid,
|
||||||
|
event2.uuid,
|
||||||
|
event3.uuid,
|
||||||
|
event4.uuid
|
||||||
|
]
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 4
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event1.uuid,
|
||||||
|
event2.uuid,
|
||||||
|
event3.uuid,
|
||||||
|
event4.uuid
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "finds 4 events : long event enabled 30 days", %{conn: conn} do
|
||||||
|
Config.put([:instance, :duration_of_long_event], 30)
|
||||||
|
now = DateTime.utc_now()
|
||||||
|
|
||||||
|
event1 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Cours 10j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 15)
|
||||||
|
)
|
||||||
|
|
||||||
|
event2 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 30j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 35)
|
||||||
|
)
|
||||||
|
|
||||||
|
event3 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 31j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 36)
|
||||||
|
)
|
||||||
|
|
||||||
|
event4 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 40j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 45)
|
||||||
|
)
|
||||||
|
|
||||||
|
Workers.BuildSearch.insert_search_event(event1)
|
||||||
|
Workers.BuildSearch.insert_search_event(event2)
|
||||||
|
Workers.BuildSearch.insert_search_event(event3)
|
||||||
|
Workers.BuildSearch.insert_search_event(event4)
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: false}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 2
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event1.uuid,
|
||||||
|
event2.uuid
|
||||||
|
]
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 2
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event3.uuid,
|
||||||
|
event4.uuid
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "finds 4 events : long event enabled 15 days", %{conn: conn} do
|
||||||
|
Config.put([:instance, :duration_of_long_event], 15)
|
||||||
|
now = DateTime.utc_now()
|
||||||
|
|
||||||
|
event1 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Cours 10j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 15)
|
||||||
|
)
|
||||||
|
|
||||||
|
event2 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 30j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 35)
|
||||||
|
)
|
||||||
|
|
||||||
|
event3 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 31j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 36)
|
||||||
|
)
|
||||||
|
|
||||||
|
event4 =
|
||||||
|
insert(:event,
|
||||||
|
title: "Long 40j",
|
||||||
|
begins_on: DateTime.add(now, 3600 * 24 * 5),
|
||||||
|
ends_on: DateTime.add(now, 3600 * 24 * 45)
|
||||||
|
)
|
||||||
|
|
||||||
|
Workers.BuildSearch.insert_search_event(event1)
|
||||||
|
Workers.BuildSearch.insert_search_event(event2)
|
||||||
|
Workers.BuildSearch.insert_search_event(event3)
|
||||||
|
Workers.BuildSearch.insert_search_event(event4)
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: false}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 1
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event1.uuid
|
||||||
|
]
|
||||||
|
|
||||||
|
res =
|
||||||
|
AbsintheHelpers.graphql_query(conn,
|
||||||
|
query: @search_events_query,
|
||||||
|
variables: %{longevents: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["searchEvents"]["total"] == 3
|
||||||
|
|
||||||
|
assert res["data"]["searchEvents"]["elements"]
|
||||||
|
|> Enum.map(& &1["uuid"]) == [
|
||||||
|
event2.uuid,
|
||||||
|
event3.uuid,
|
||||||
|
event4.uuid
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
test "finds events with multiple criteria", %{conn: conn} do
|
test "finds events with multiple criteria", %{conn: conn} do
|
||||||
{lon, lat} = {45.75, 4.85}
|
{lon, lat} = {45.75, 4.85}
|
||||||
point = %Geo.Point{coordinates: {lon, lat}, srid: 4326}
|
point = %Geo.Point{coordinates: {lon, lat}, srid: 4326}
|
||||||
|
|
|
@ -49,6 +49,7 @@ export const configMock = {
|
||||||
},
|
},
|
||||||
countryCode: "fr",
|
countryCode: "fr",
|
||||||
demoMode: false,
|
demoMode: false,
|
||||||
|
longEvents: false,
|
||||||
description: "Mobilizon.fr est l'instance Mobilizon de Framasoft.",
|
description: "Mobilizon.fr est l'instance Mobilizon de Framasoft.",
|
||||||
features: {
|
features: {
|
||||||
__typename: "Features",
|
__typename: "Features",
|
||||||
|
|
Loading…
Reference in New Issue