Allow to join an open group
Also: * Refactor interacting with a remote event so that you can interact with a remote group as well * Add a setting for group admins to pick between an open and invite-only group * Fix new groups without posts/todos/resources/events/conversations URL set * Repair local groups that haven't got their posts/todos/resources/events/conversations URL set * Add a scheduled job to refresh remote groups every hour * Add a user setting to pick when to receive notifications when there's new members to approve (will be used when this feature is available) * Fix pagination for members Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -42,7 +42,7 @@ export class Actor implements IActor {
|
||||
|
||||
type: ActorType = ActorType.PERSON;
|
||||
|
||||
constructor(hash: IActor | {} = {}) {
|
||||
constructor(hash: IActor | Record<any, unknown> = {}) {
|
||||
Object.assign(this, hash);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,10 @@ export enum MemberRole {
|
||||
REJECTED = "REJECTED",
|
||||
}
|
||||
|
||||
export interface IGroup extends IActor {
|
||||
members: Paginate<IMember>;
|
||||
resources: Paginate<IResource>;
|
||||
todoLists: Paginate<ITodoList>;
|
||||
discussions: Paginate<IDiscussion>;
|
||||
organizedEvents: Paginate<IEvent>;
|
||||
physicalAddress: IAddress;
|
||||
export enum Openness {
|
||||
INVITE_ONLY = "INVITE_ONLY",
|
||||
MODERATED = "MODERATED",
|
||||
OPEN = "OPEN",
|
||||
}
|
||||
|
||||
export interface IMember {
|
||||
@@ -37,6 +34,16 @@ export interface IMember {
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface IGroup extends IActor {
|
||||
members: Paginate<IMember>;
|
||||
resources: Paginate<IResource>;
|
||||
todoLists: Paginate<ITodoList>;
|
||||
discussions: Paginate<IDiscussion>;
|
||||
organizedEvents: Paginate<IEvent>;
|
||||
physicalAddress: IAddress;
|
||||
openness: Openness;
|
||||
}
|
||||
|
||||
export class Group extends Actor implements IGroup {
|
||||
members: Paginate<IMember> = { elements: [], total: 0 };
|
||||
|
||||
@@ -50,16 +57,18 @@ export class Group extends Actor implements IGroup {
|
||||
|
||||
posts: Paginate<IPost> = { elements: [], total: 0 };
|
||||
|
||||
constructor(hash: IGroup | {} = {}) {
|
||||
constructor(hash: IGroup | Record<string, unknown> = {}) {
|
||||
super(hash);
|
||||
this.type = ActorType.GROUP;
|
||||
|
||||
this.patch(hash);
|
||||
}
|
||||
|
||||
openness: Openness = Openness.INVITE_ONLY;
|
||||
|
||||
physicalAddress: IAddress = new Address();
|
||||
|
||||
patch(hash: any) {
|
||||
patch(hash: IGroup | Record<string, unknown>): void {
|
||||
Object.assign(this, hash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ICurrentUser } from "../current-user.model";
|
||||
import { IEvent, IParticipant } from "../event.model";
|
||||
import { IEvent } from "../event.model";
|
||||
import { Actor, IActor } from "./actor.model";
|
||||
import { Paginate } from "../paginate";
|
||||
import { IMember } from "./group.model";
|
||||
import { IParticipant } from "../participant.model";
|
||||
|
||||
export interface IFeedToken {
|
||||
token: string;
|
||||
@@ -29,13 +30,13 @@ export class Person extends Actor implements IPerson {
|
||||
|
||||
user!: ICurrentUser;
|
||||
|
||||
constructor(hash: IPerson | {} = {}) {
|
||||
constructor(hash: IPerson | Record<string, unknown> = {}) {
|
||||
super(hash);
|
||||
|
||||
this.patch(hash);
|
||||
}
|
||||
|
||||
patch(hash: any) {
|
||||
patch(hash: IPerson | Record<string, unknown>): void {
|
||||
Object.assign(this, hash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IEvent, IParticipant } from "@/types/event.model";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { IPerson } from "@/types/actor/person.model";
|
||||
import { Paginate } from "./paginate";
|
||||
import { IParticipant } from "./participant.model";
|
||||
|
||||
export enum ICurrentUserRole {
|
||||
USER = "USER",
|
||||
@@ -16,7 +17,7 @@ export interface ICurrentUser {
|
||||
defaultActor?: IPerson;
|
||||
}
|
||||
|
||||
export enum INotificationPendingParticipationEnum {
|
||||
export enum INotificationPendingEnum {
|
||||
NONE = "NONE",
|
||||
DIRECT = "DIRECT",
|
||||
ONE_DAY = "ONE_DAY",
|
||||
@@ -28,7 +29,8 @@ export interface IUserSettings {
|
||||
notificationOnDay: boolean;
|
||||
notificationEachWeek: boolean;
|
||||
notificationBeforeEvent: boolean;
|
||||
notificationPendingParticipation: INotificationPendingParticipationEnum;
|
||||
notificationPendingParticipation: INotificationPendingEnum;
|
||||
notificationPendingMembership: INotificationPendingEnum;
|
||||
}
|
||||
|
||||
export interface IUser extends ICurrentUser {
|
||||
|
||||
61
js/src/types/event-options.model.ts
Normal file
61
js/src/types/event-options.model.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export interface IParticipationCondition {
|
||||
title: string;
|
||||
content: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface IOffer {
|
||||
price: number;
|
||||
priceCurrency: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export enum CommentModeration {
|
||||
ALLOW_ALL = "ALLOW_ALL",
|
||||
MODERATED = "MODERATED",
|
||||
CLOSED = "CLOSED",
|
||||
}
|
||||
|
||||
export interface IEventOptions {
|
||||
maximumAttendeeCapacity: number;
|
||||
remainingAttendeeCapacity: number;
|
||||
showRemainingAttendeeCapacity: boolean;
|
||||
anonymousParticipation: boolean;
|
||||
hideOrganizerWhenGroupEvent: boolean;
|
||||
offers: IOffer[];
|
||||
participationConditions: IParticipationCondition[];
|
||||
attendees: string[];
|
||||
program: string;
|
||||
commentModeration: CommentModeration;
|
||||
showParticipationPrice: boolean;
|
||||
showStartTime: boolean;
|
||||
showEndTime: boolean;
|
||||
}
|
||||
|
||||
export class EventOptions implements IEventOptions {
|
||||
maximumAttendeeCapacity = 0;
|
||||
|
||||
remainingAttendeeCapacity = 0;
|
||||
|
||||
showRemainingAttendeeCapacity = false;
|
||||
|
||||
anonymousParticipation = false;
|
||||
|
||||
hideOrganizerWhenGroupEvent = false;
|
||||
|
||||
offers: IOffer[] = [];
|
||||
|
||||
participationConditions: IParticipationCondition[] = [];
|
||||
|
||||
attendees: string[] = [];
|
||||
|
||||
program = "";
|
||||
|
||||
commentModeration = CommentModeration.ALLOW_ALL;
|
||||
|
||||
showParticipationPrice = false;
|
||||
|
||||
showStartTime = true;
|
||||
|
||||
showEndTime = true;
|
||||
}
|
||||
@@ -3,7 +3,9 @@ import { ITag } from "@/types/tag.model";
|
||||
import { IPicture } from "@/types/picture.model";
|
||||
import { IComment } from "@/types/comment.model";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
import { Actor, Group, IActor, IPerson } from "./actor";
|
||||
import { Actor, Group, IActor, IGroup, IPerson } from "./actor";
|
||||
import { IParticipant } from "./participant.model";
|
||||
import { EventOptions, IEventOptions } from "./event-options.model";
|
||||
|
||||
export enum EventStatus {
|
||||
TENTATIVE = "TENTATIVE",
|
||||
@@ -30,16 +32,6 @@ export enum EventVisibilityJoinOptions {
|
||||
LIMITED = "LIMITED",
|
||||
}
|
||||
|
||||
export enum ParticipantRole {
|
||||
NOT_APPROVED = "NOT_APPROVED",
|
||||
NOT_CONFIRMED = "NOT_CONFIRMED",
|
||||
REJECTED = "REJECTED",
|
||||
PARTICIPANT = "PARTICIPANT",
|
||||
MODERATOR = "MODERATOR",
|
||||
ADMINISTRATOR = "ADMINISTRATOR",
|
||||
CREATOR = "CREATOR",
|
||||
}
|
||||
|
||||
export enum Category {
|
||||
BUSINESS = "business",
|
||||
CONFERENCE = "conference",
|
||||
@@ -56,58 +48,6 @@ export interface IEventCardOptions {
|
||||
memberofGroup: boolean;
|
||||
}
|
||||
|
||||
export interface IParticipant {
|
||||
id?: string;
|
||||
role: ParticipantRole;
|
||||
actor: IActor;
|
||||
event: IEvent;
|
||||
metadata: { cancellationToken?: string; message?: string };
|
||||
insertedAt?: Date;
|
||||
}
|
||||
|
||||
export class Participant implements IParticipant {
|
||||
id?: string;
|
||||
|
||||
event!: IEvent;
|
||||
|
||||
actor!: IActor;
|
||||
|
||||
role: ParticipantRole = ParticipantRole.NOT_APPROVED;
|
||||
|
||||
metadata = {};
|
||||
|
||||
insertedAt?: Date;
|
||||
|
||||
constructor(hash?: IParticipant) {
|
||||
if (!hash) return;
|
||||
|
||||
this.id = hash.id;
|
||||
this.event = new EventModel(hash.event);
|
||||
this.actor = new Actor(hash.actor);
|
||||
this.role = hash.role;
|
||||
this.metadata = hash.metadata;
|
||||
this.insertedAt = hash.insertedAt;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOffer {
|
||||
price: number;
|
||||
priceCurrency: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface IParticipationCondition {
|
||||
title: string;
|
||||
content: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export enum CommentModeration {
|
||||
ALLOW_ALL = "ALLOW_ALL",
|
||||
MODERATED = "MODERATED",
|
||||
CLOSED = "CLOSED",
|
||||
}
|
||||
|
||||
export interface IEventParticipantStats {
|
||||
notApproved: number;
|
||||
notConfirmed: number;
|
||||
@@ -119,6 +59,26 @@ export interface IEventParticipantStats {
|
||||
going: number;
|
||||
}
|
||||
|
||||
interface IEventEditJSON {
|
||||
id?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
beginsOn: string;
|
||||
endsOn: string | null;
|
||||
status: EventStatus;
|
||||
visibility: EventVisibility;
|
||||
joinOptions: EventJoinOptions;
|
||||
draft: boolean;
|
||||
picture: IPicture | { pictureId: string } | null;
|
||||
attributedToId: string | null;
|
||||
onlineAddress?: string;
|
||||
phoneAddress?: string;
|
||||
physicalAddress?: IAddress;
|
||||
tags: string[];
|
||||
options: IEventOptions;
|
||||
contacts: { id?: string }[];
|
||||
}
|
||||
|
||||
export interface IEvent {
|
||||
id?: string;
|
||||
uuid: string;
|
||||
@@ -139,7 +99,7 @@ export interface IEvent {
|
||||
picture: IPicture | null;
|
||||
|
||||
organizerActor?: IActor;
|
||||
attributedTo?: IActor;
|
||||
attributedTo?: IGroup;
|
||||
participantStats: IEventParticipantStats;
|
||||
participants: Paginate<IParticipant>;
|
||||
|
||||
@@ -157,50 +117,6 @@ export interface IEvent {
|
||||
toEditJSON(): IEventEditJSON;
|
||||
}
|
||||
|
||||
export interface IEventOptions {
|
||||
maximumAttendeeCapacity: number;
|
||||
remainingAttendeeCapacity: number;
|
||||
showRemainingAttendeeCapacity: boolean;
|
||||
anonymousParticipation: boolean;
|
||||
hideOrganizerWhenGroupEvent: boolean;
|
||||
offers: IOffer[];
|
||||
participationConditions: IParticipationCondition[];
|
||||
attendees: string[];
|
||||
program: string;
|
||||
commentModeration: CommentModeration;
|
||||
showParticipationPrice: boolean;
|
||||
showStartTime: boolean;
|
||||
showEndTime: boolean;
|
||||
}
|
||||
|
||||
export class EventOptions implements IEventOptions {
|
||||
maximumAttendeeCapacity = 0;
|
||||
|
||||
remainingAttendeeCapacity = 0;
|
||||
|
||||
showRemainingAttendeeCapacity = false;
|
||||
|
||||
anonymousParticipation = false;
|
||||
|
||||
hideOrganizerWhenGroupEvent = false;
|
||||
|
||||
offers: IOffer[] = [];
|
||||
|
||||
participationConditions: IParticipationCondition[] = [];
|
||||
|
||||
attendees: string[] = [];
|
||||
|
||||
program = "";
|
||||
|
||||
commentModeration = CommentModeration.ALLOW_ALL;
|
||||
|
||||
showParticipationPrice = false;
|
||||
|
||||
showStartTime = true;
|
||||
|
||||
showEndTime = true;
|
||||
}
|
||||
|
||||
export class EventModel implements IEvent {
|
||||
id?: string;
|
||||
|
||||
@@ -255,7 +171,7 @@ export class EventModel implements IEvent {
|
||||
|
||||
comments: IComment[] = [];
|
||||
|
||||
attributedTo?: IActor = new Actor();
|
||||
attributedTo?: IGroup = new Group();
|
||||
|
||||
organizerActor?: IActor = new Actor();
|
||||
|
||||
@@ -323,7 +239,6 @@ export class EventModel implements IEvent {
|
||||
phoneAddress: this.phoneAddress,
|
||||
physicalAddress: this.physicalAddress,
|
||||
options: this.options,
|
||||
// organizerActorId: this.organizerActor && this.organizerActor.id ? this.organizerActor.id : null,
|
||||
attributedToId: this.attributedTo && this.attributedTo.id ? this.attributedTo.id : null,
|
||||
contacts: this.contacts.map(({ id }) => ({
|
||||
id,
|
||||
@@ -331,23 +246,3 @@ export class EventModel implements IEvent {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface IEventEditJSON {
|
||||
id?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
beginsOn: string;
|
||||
endsOn: string | null;
|
||||
status: EventStatus;
|
||||
visibility: EventVisibility;
|
||||
joinOptions: EventJoinOptions;
|
||||
draft: boolean;
|
||||
picture: IPicture | { pictureId: string } | null;
|
||||
attributedToId: string | null;
|
||||
onlineAddress?: string;
|
||||
phoneAddress?: string;
|
||||
physicalAddress?: IAddress;
|
||||
tags: string[];
|
||||
options: IEventOptions;
|
||||
contacts: { id?: string }[];
|
||||
}
|
||||
|
||||
46
js/src/types/participant.model.ts
Normal file
46
js/src/types/participant.model.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Actor, IActor } from "./actor";
|
||||
import { EventModel, IEvent } from "./event.model";
|
||||
|
||||
export enum ParticipantRole {
|
||||
NOT_APPROVED = "NOT_APPROVED",
|
||||
NOT_CONFIRMED = "NOT_CONFIRMED",
|
||||
REJECTED = "REJECTED",
|
||||
PARTICIPANT = "PARTICIPANT",
|
||||
MODERATOR = "MODERATOR",
|
||||
ADMINISTRATOR = "ADMINISTRATOR",
|
||||
CREATOR = "CREATOR",
|
||||
}
|
||||
|
||||
export interface IParticipant {
|
||||
id?: string;
|
||||
role: ParticipantRole;
|
||||
actor: IActor;
|
||||
event: IEvent;
|
||||
metadata: { cancellationToken?: string; message?: string };
|
||||
insertedAt?: Date;
|
||||
}
|
||||
|
||||
export class Participant implements IParticipant {
|
||||
id?: string;
|
||||
|
||||
event!: IEvent;
|
||||
|
||||
actor!: IActor;
|
||||
|
||||
role: ParticipantRole = ParticipantRole.NOT_APPROVED;
|
||||
|
||||
metadata = {};
|
||||
|
||||
insertedAt?: Date;
|
||||
|
||||
constructor(hash?: IParticipant) {
|
||||
if (!hash) return;
|
||||
|
||||
this.id = hash.id;
|
||||
this.event = new EventModel(hash.event);
|
||||
this.actor = new Actor(hash.actor);
|
||||
this.role = hash.role;
|
||||
this.metadata = hash.metadata;
|
||||
this.insertedAt = hash.insertedAt;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user