interface specs
This commit is contained in:
parent
a876eab9f3
commit
f889985326
12
.gitignore
vendored
12
.gitignore
vendored
@ -5,3 +5,15 @@
|
||||
*~
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
# Old OS3 files and folders
|
||||
.coverage
|
||||
.mypy_cache
|
||||
Compodoc
|
||||
__pycache__
|
||||
bower_components
|
||||
client
|
||||
make
|
||||
openslides*
|
||||
personal_data
|
||||
tests
|
||||
|
27
docs/interfaces/action-service.txt
Normal file
27
docs/interfaces/action-service.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# Action Service Interface
|
||||
|
||||
// TODO: More Exceptions?
|
||||
Exception ActionNotFound(name: string);
|
||||
|
||||
|
||||
/**
|
||||
* Executes multiple actions in the conext of the user given by the user_id.
|
||||
*
|
||||
* @throws ActionNotFound
|
||||
*/
|
||||
execute(actions: Action[], user_id: number): ExecuteResult;
|
||||
|
||||
interface Action {
|
||||
name: string;
|
||||
data: object;
|
||||
}
|
||||
|
||||
interface ActionError {
|
||||
error: string;
|
||||
argumens: string[];
|
||||
}
|
||||
|
||||
// Gives a detailed error, for all failed actions. For some actions, success
|
||||
// data is returned (the object). If there is no success data, null is given
|
||||
// for the action. The results index matches to the action index in the request.
|
||||
Type ExecuteResult = (ActionError | object | null)[]
|
200
docs/interfaces/datastore-service.txt
Normal file
200
docs/interfaces/datastore-service.txt
Normal file
@ -0,0 +1,200 @@
|
||||
# Datastore Interface
|
||||
|
||||
Enum EventType {
|
||||
Create,
|
||||
Update,
|
||||
DeleteField,
|
||||
Delete,
|
||||
Restore,
|
||||
}
|
||||
|
||||
Exception ModelDoesNotExist(model: Fqid);
|
||||
Exception ModelExist(model: Fqid);
|
||||
Exception ModelNotDeleted(model: Fqid);
|
||||
Exception ModelLocked(model: Fqid | CollectionField);
|
||||
Exception InvalidFormat();
|
||||
|
||||
// TODO:
|
||||
Exception MeetingIdNotSpecified();
|
||||
|
||||
## Writer
|
||||
|
||||
/**
|
||||
* Writes Events into the datastore
|
||||
*
|
||||
* @throws ModelDoesNotExist
|
||||
* @throws ModelExists
|
||||
* @throws ModelLocked
|
||||
* @throws InvalidFormat
|
||||
* @throws ModelNotDeleted
|
||||
*/
|
||||
write(request: WriteRequest): void publishes BulkMetadataUpdate
|
||||
|
||||
Interface WriteRequest {
|
||||
events: (CreateEvent | RestoreEvent | UpdateEvent | DeleteEvent)[];
|
||||
information: {
|
||||
<fqid>: Object
|
||||
};
|
||||
user_id: number;
|
||||
locked_fields: {
|
||||
<fqid>: Position;
|
||||
<CollectionField>: Position;
|
||||
}
|
||||
}
|
||||
|
||||
Interface CreateEvent {
|
||||
fqid: Fqid;
|
||||
data: {
|
||||
<field>: Value;
|
||||
}
|
||||
}
|
||||
|
||||
Interface UpdateEvent {
|
||||
fqfields: {
|
||||
<fqfield>: Value;
|
||||
}
|
||||
}
|
||||
|
||||
Interface RestoreEvent {
|
||||
fqid: Fqid;
|
||||
}
|
||||
|
||||
Interface DeleteEvent {
|
||||
fqid: Fqid;
|
||||
}
|
||||
|
||||
Event FieldUpdatedEvent on topic FieldUpdatedTopic {
|
||||
created: Fqid[];
|
||||
deleted: Fqid[];
|
||||
updated: Fqfield[];
|
||||
}
|
||||
|
||||
## Reader
|
||||
|
||||
/** Common Parameters:
|
||||
* - position: Optionsl, if given reads the data to this position.
|
||||
* - mapped_fields: List of fields, that should onl be present in the response.
|
||||
* TODO:
|
||||
* - meeting_id: Für Modelle außer Nutzer, Gremium, Veranstaltung und Config
|
||||
* Ist eine Angabe verpflichtend. Dies beschränkt die Nutzung
|
||||
* auf eine spezifische Veranstaltung.
|
||||
*
|
||||
* Alle Operationen fügen `meta:position` und `meta:deleted` an.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a model. Deleted models are not returned (and handled as a ModelDiesNotExit)
|
||||
*
|
||||
* @throws ModelDoesNotExist
|
||||
*/
|
||||
get(model: Fqid, position?: Position, mapped_fields?: fields[]): Partial<Model>;
|
||||
|
||||
/**
|
||||
* Analogous to `get`, but also finds deleted models (see `meta_deleted` in the model)
|
||||
*
|
||||
* @throws ModelDoesNotExist
|
||||
*/
|
||||
getWithDeleted(model: Fqid, position?: Position, mapped_fields?: Field[]): Partial<Model>;
|
||||
|
||||
/**
|
||||
* Gibt mehrere Modellinstanzen aus dem Eventstore zur aktuellen Position
|
||||
* zurück. Gelöschte Instanzen werden nicht zurückgegeben.
|
||||
*
|
||||
* @throws ModelDoesNotExist
|
||||
*/
|
||||
getMany(collection: Collection, ids: Id[], position?: Position, mapped_fields?: Field[]): Partial<Model>[];
|
||||
|
||||
/**
|
||||
* Analog zu `getMany`, gibt jedoch auch gelöschte Instanzen zurück.
|
||||
*
|
||||
* @throws ModelDoesNotExist
|
||||
*/
|
||||
getManyWithDeleted(collection: Collection, ids: Id[], position?: Position, mapped_fields?: Field[]): Partial<Model>[];
|
||||
|
||||
// Shortcuts for `filter*` without a filter
|
||||
/**
|
||||
* Gibt alle Modelle einer Collection zurück. Die Veranstaltungsid ist zwingend (s.o.)
|
||||
* für einige Collections. Gibt keine gelöscheten Elemente aus.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
getAll(collection: Collection, meeting_id?: Id, position?: Position, mapped_fields?: Field[]): Partial<Model>[];
|
||||
|
||||
/**
|
||||
* Wie `getAll`, gibt gelöschte und nicht-gelöschte Modelle wieder.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
getAllWithDeleted(collection: Collection, meeting_id?: Id, position?: Position, mapped_fields?: Field[]): Partial<Model>[];
|
||||
|
||||
/**
|
||||
* Wie `getAll`, gibt jedoch nur gelöschte Modelle wieder.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
getAllOnlyDeleted(collection: Collection, meeting_id?: Id, position?: Position, mapped_fields?: Field[]): Partial<Model>[];
|
||||
|
||||
/**
|
||||
* Gibt alle Modelle einer Collection (möglicherweise Veranstaltungsspezifisch)
|
||||
* wieder, die dem filter-Ausdruck genügen. Für Filtermöglichkeiten: siehe unten.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
filter(collection: Collection, meeting_id?: Id, filter: Filter, position?: Position, mapped_fields?: Field[]): Partial<Model>[]
|
||||
|
||||
/**
|
||||
* Siehe `filter`. Gibt zurück, ob mindestens ein Modell gefunden wurde.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
exists(collection: Collection, meeting_id?: Id, filter: Filter, position?: Position): {exists: boolean; position: Position;}
|
||||
|
||||
/**
|
||||
* Siehe `filter`. Gibt die Anzahl an Modellen zurück.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
*/
|
||||
count(collection: Collection, meeting_id?: Id, filter: Filter, position?: Position): {count: number; position: Position;}
|
||||
|
||||
/**
|
||||
* Führt einfache Min-Max-Aggregation über numerische Felder aus.
|
||||
*
|
||||
* @throws MeetingIdNotSpecified()
|
||||
* @throws AggregationOperationInvalid(operand, value)
|
||||
*/
|
||||
aggregate(collection: Collection, meeting_id?: Id, filter: Filter, aggregate: Aggregate, position?: Position): Value
|
||||
|
||||
Type Filter = And | Or | Not | FilterOperator
|
||||
|
||||
/**
|
||||
* Das eigentliche Filter-predikat. M[field] ist der Wert des Feldes des
|
||||
* betrachteten Modells. Für alle Operatoren ist das
|
||||
* Prädikat wahr, wenn `M[field] <op> value` wahr ist.
|
||||
*/
|
||||
Interface FilterOperator {
|
||||
field: Field;
|
||||
value: Value | null;
|
||||
operator: '==' | '!=' | '<' | '>' | '>=' | '<=';
|
||||
}
|
||||
|
||||
Interface Not {
|
||||
not: Filter;
|
||||
}
|
||||
|
||||
Interface And {
|
||||
and: Filter[];
|
||||
}
|
||||
|
||||
Interface Or {
|
||||
or: Filter[];
|
||||
}
|
||||
|
||||
Interface Aggregate {
|
||||
field: Field;
|
||||
type: 'min' | 'max';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt n sequentielle Ids für die gegebene Collection zurück.
|
||||
*/
|
||||
getId(collection: Collection, n: number): Id
|
68
docs/interfaces/how-to.txt
Normal file
68
docs/interfaces/how-to.txt
Normal file
@ -0,0 +1,68 @@
|
||||
## How to specify an interface for a service?
|
||||
|
||||
There are many ways to describe, what a service should do. The main
|
||||
characteristics (from an outside-view) are the provided functions. Each service
|
||||
does have functions to execute with arguments and return types. Next to the
|
||||
returnvalue, events can be published or errors be thrown. The way we want to
|
||||
derscribe these interfaces is through a TypeScript-like interface definition.
|
||||
The interface is the collection of all functions defined.
|
||||
|
||||
Example:
|
||||
/**
|
||||
* The Exception, if a model wasn't found. The missed id is given.
|
||||
*/
|
||||
Exception ObjectNotFound(id: Id);
|
||||
|
||||
/**
|
||||
* Does something..
|
||||
*
|
||||
* @throws ObjectNotFound
|
||||
do_it(data: MyRequest): void publishes MyEvent;
|
||||
|
||||
interface MyRequest {
|
||||
id: Id;
|
||||
text: string;
|
||||
some_other_value: number;
|
||||
}
|
||||
|
||||
Event MyEvent on topic MyEventTopic {
|
||||
changed_text: string;
|
||||
}
|
||||
|
||||
There are some common types defined here:
|
||||
Type Position=number;
|
||||
Type Id=number;
|
||||
Type Fqid=string; // `collection/id`
|
||||
Type Fqfield=string; // `collection/id/field`
|
||||
Type Collection=string; // `collection`
|
||||
Type CollectionField=string; // `collection/field`
|
||||
Type Model=object;
|
||||
Type Field=string;
|
||||
Type Value=any;
|
||||
|
||||
The language is a bit modified:
|
||||
|
||||
1) Exceptions
|
||||
Exceptions should be declared by giving the name and parameters:
|
||||
# Exception <name>(<param1>: <type1>, ...);
|
||||
A comment should state, why this exception can be thrown
|
||||
|
||||
2) Events in the function declaration
|
||||
Each function takes some arguments and have a return type. Next to the
|
||||
return type, some events can be published. With the `publishes` token, one
|
||||
can give a comma seperated list of events, that can be generated.
|
||||
# my_function(): void publishes Event1, Event2
|
||||
|
||||
Events should be specified as interfaces, but named `Events`. Also there is
|
||||
the `on topic` token, on which topic the message is broadcasted.
|
||||
# Event MyEvent on topic MyEventTopic { ... }
|
||||
|
||||
3) Functiondocumentation
|
||||
Each function must have a description. Also it should tell, what exceptions
|
||||
could be thrown.
|
||||
|
||||
4) Placeholders
|
||||
If you need generic names, use placeholders: `<my_placeholder>`
|
||||
E.g. if the event topic is specific for one id, the topic used may be
|
||||
definied as this example:
|
||||
# Event MyEvent on topic MyEventForUser<user_id> { ... }
|
1
docs/modellierung.drawio
Normal file
1
docs/modellierung.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="www.draw.io" modified="2020-01-20T11:13:06.980Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36" version="12.5.5" etag="lo63t2GCt8XfH-bbtAHo"><diagram id="SzigwTKClLag4ZUmXMWD" name="Page-1">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</diagram></mxfile>
|
633
docs/models.txt
Normal file
633
docs/models.txt
Normal file
@ -0,0 +1,633 @@
|
||||
Types:
|
||||
Nativ: null, string, number, JSON
|
||||
Fqid: Strukturierter string
|
||||
HTML: string mit HTML Inhalt
|
||||
<T>[]: Array von Typ T
|
||||
<modellname>: number (ID) zu dem Modell
|
||||
float: string mit iso-gemäßer Formatierung eines floats
|
||||
decimal(X): Decimal values represented as a string with X decimal places
|
||||
datetime: Datetime as a unix timestamp
|
||||
// Why a number? This enables queries in the DB. And we do not
|
||||
// need more precision than 1 second.
|
||||
|
||||
Note to structured fields: Fields with `some_field_<some_variable>` do have
|
||||
values for `<some_variable>` that fits into the format of a field. E.g.
|
||||
`amendment_paragraph_3`. Note that it might be possible that no kind of
|
||||
this field exists in a model.
|
||||
|
||||
Interface projector {
|
||||
id: number;
|
||||
scale: number;
|
||||
scroll: number;
|
||||
name: string;
|
||||
width: number;
|
||||
aspect_ratio_numerator: number;
|
||||
aspect_ratio_denominator: number;
|
||||
color: string;
|
||||
background_color: string;
|
||||
header_background_color: string;
|
||||
header_font_color: string;
|
||||
header_h1_color: string;
|
||||
chyron_background_color: string;
|
||||
chyron_font_color: string;
|
||||
show_header_footer: boolean;
|
||||
show_title: boolean;
|
||||
show_logo: boolean
|
||||
|
||||
element: projection;
|
||||
element_fqid: Fqid;
|
||||
elements_preview: projection[];
|
||||
elements_history: projection[];
|
||||
reference_projector_id: projector;
|
||||
projectiondefault_ids: projectiondefault[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface projection {
|
||||
id: number;
|
||||
projector_id: projector;
|
||||
projector_history_ids: projector;
|
||||
projector_preview_id: projector;
|
||||
element: Fqid;
|
||||
options: JSON;
|
||||
}
|
||||
Interface projectiondefault {
|
||||
id: number;
|
||||
name: string;
|
||||
display_name: string;
|
||||
|
||||
projector_id: projector;
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface tag {
|
||||
id: number;
|
||||
name: string;
|
||||
|
||||
tagged_ids: Fqid[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface projector_message {
|
||||
id: number;
|
||||
message: HTML;
|
||||
|
||||
projection_id: projection[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface projector_countdown {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
default_time: number;
|
||||
countdown_time: number; // float?
|
||||
running: boolean;
|
||||
|
||||
projection_id: projection[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface agenda_item {
|
||||
id: number;
|
||||
item_number: string;
|
||||
comment: string,
|
||||
closed: boolean,
|
||||
type: number,
|
||||
is_internal: boolean;
|
||||
is_hidden: boolean;
|
||||
duration: number; // in seconds
|
||||
weight: number;
|
||||
level: number; //für client nicht unbedingt nötig.
|
||||
|
||||
content_object_id: Fqid;
|
||||
parent_id: agenda_item;
|
||||
children_ids: agenda_item[];
|
||||
projection_id: projection[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface list_of_speakers {
|
||||
closed: boolean;
|
||||
|
||||
content_object_id: Fqid;
|
||||
speaker_ids: speaker[];
|
||||
projection_id: projection[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface speaker {
|
||||
id: number;
|
||||
begin_time: datetime;
|
||||
end_time: datetime;
|
||||
weight: number;
|
||||
marked: boolean;
|
||||
|
||||
list_of_speakers_id: list_of_speakers;
|
||||
user_id: user;
|
||||
}
|
||||
Interface topic {
|
||||
id: number;
|
||||
title: string;
|
||||
text: HTML;
|
||||
|
||||
attachments_id: mediafile[];
|
||||
agenda_item_id: agenda_item;
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface user {
|
||||
id: number;
|
||||
username: string;
|
||||
last_email_send: string;
|
||||
is_active: boolean; // TODO @emanuel: Ist ein Nutzer systemweit (organisationsweit) aktiv/inaktiv?
|
||||
default_password: string;
|
||||
is_committee: boolean;
|
||||
about_me: HTML;
|
||||
gender: string,
|
||||
// TODO: auth
|
||||
//auth_type: string;
|
||||
// auth-spezifische felder?
|
||||
title: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
comment: HTML;
|
||||
number: string;
|
||||
email: string;
|
||||
structure_level: string;
|
||||
|
||||
role_id: role; // Attention: prevent impelenting a "default-role" or let a
|
||||
// user create such a role! This would cause the user_ids-array for this
|
||||
// role to explode in size. If a user has no role, it should be handles as
|
||||
// the user has no permission in the organisation and is a "normal" delegate
|
||||
// there. Just a few users (expected <100) should even get a role and all
|
||||
// other don't.
|
||||
|
||||
|
||||
is_present_in_meeting_ids: meeting[];
|
||||
meeting_id: meeting; // Temporary users
|
||||
|
||||
// All foreign keys are meeting-specific:
|
||||
// - Keys are smaller (Space is in O(n^2) for n keys
|
||||
// in the relation), so this saves storagespace
|
||||
// - This makes quering things like this possible:
|
||||
// "Give me all groups for User X in Meeting Y" without
|
||||
// the need to get all groups and filter them for the meeting
|
||||
group_<meeting_id>_ids: group[];
|
||||
personal_note_<meeting_id>_ids: personal_note[];
|
||||
projection_<meeting_id>_ids: projection[];
|
||||
supported_motion_<meeting_id>_ids: motion[];
|
||||
submitted_motion_<meeting_id>_ids: motion_submitter[];
|
||||
assignment_related_user_<meeting_id>_ids: assignment_related_user[];
|
||||
motion_vote_<meeting_id>_ids: motion_vote[];
|
||||
assignment_vote_<meeting_id>_ids: assignment_vote[];
|
||||
motion_voted_poll_<meeting_id>_ids: motion_poll[];
|
||||
assignment_voted_poll_<meeting_id>_ids: assignment_poll[];
|
||||
}
|
||||
Interface group {
|
||||
id: number;
|
||||
name: string;
|
||||
is_superadmin_group: boolean;
|
||||
is_default_group: boolean;
|
||||
permissions: string[];
|
||||
|
||||
user_ids: user[];
|
||||
mediafile_access_group_ids: mediafile[];
|
||||
read_comment_section_ids: motion_comment_section[];
|
||||
write_comment_section_ids: motion_comment_section[];
|
||||
motion_poll_ids: motion_poll[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface personal_note {
|
||||
id: number;
|
||||
note: HTML;
|
||||
star: boolean;
|
||||
|
||||
user_id: user;
|
||||
element: Fqid;
|
||||
meeting_id: meeting;
|
||||
}
|
||||
// Mediafiles are delivered by the mediafile server with the URL
|
||||
// `<media-prefix>/media/<meeting_id>/path`
|
||||
Interface mediafile {
|
||||
id: number;
|
||||
title: string;
|
||||
is_directory: boolean;
|
||||
filesize: number; // Note: in bytes, not the human readable format anymore
|
||||
filename: string; // Note: The uploaded filename. Filename and parent_id
|
||||
// must be unique as well as title and parent_id must be unique.
|
||||
mimetype: string;
|
||||
create_timestamp: datetime;
|
||||
path: string; // Note: calcuated
|
||||
inherited_access_group_ids: boolean | number[]; // Note: calculated and no
|
||||
// reverse-relation for the gorup ids.
|
||||
|
||||
access_group_ids: group[];
|
||||
parent_id: mediafile;
|
||||
children_ids: mediafile[];
|
||||
list_of_speakers_id: list_of_speakers;
|
||||
projection_ids: projection[];
|
||||
attachement_ids: Fqid[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
// New: Resource
|
||||
// Resources are meeting-specific or organsation wide.
|
||||
// For organisation-resources, no permission chacks are done (event the user
|
||||
// must not be logged in). If a meeting-resource is requested, it is checked, if
|
||||
// the user can see the meeting (Anonymous, guest, member).
|
||||
// A resource has a token, e.g. `web_header` or `pdf_font_italic`, so the client
|
||||
// knowns, where to put the resource. They are delivered by the mediafile server
|
||||
// with the URL `<media-prefix>/resource/<id>`
|
||||
Interface Resource {
|
||||
id: number;
|
||||
token: string;
|
||||
filesize: number;
|
||||
mimetype: string;
|
||||
|
||||
// Either the meeting is set, or the organsation.
|
||||
meeting_id: meeting;
|
||||
organisation_id: organisation;
|
||||
}
|
||||
Interface motion {
|
||||
id: number;
|
||||
identifier: string;
|
||||
title: string;
|
||||
text: HTML;
|
||||
amendment_paragraph_<paragraph_number>: HTML;
|
||||
modified_final_version: HTML;
|
||||
reason: HTML;
|
||||
category_weight: number;
|
||||
state_extension: string;
|
||||
recommendation_extension: string;
|
||||
sort_parent_id: motion;
|
||||
sort_weight: number;
|
||||
created: string;
|
||||
last_modified: string;
|
||||
|
||||
parent_id: motion;
|
||||
children_ids: motion[];
|
||||
origin_id: motion;
|
||||
derived_motion_ids: motion[];
|
||||
state_id: motion_state;
|
||||
workflow_id: motion_workflow;
|
||||
recommendation_id: motion_state;
|
||||
category_id: category;
|
||||
motion_block_id: motion_block;
|
||||
submitter_ids: motion_submitter[];
|
||||
supporter_ids: user[];
|
||||
poll_ids: motion_poll[];
|
||||
change_recommendation_ids: motion_change_recommendation[];
|
||||
statute_paragraph_id: motion_statute_paragraph;
|
||||
comment_ids: motion_comment[];
|
||||
agenda_item_id: agenda_item;
|
||||
list_of_speakers_id: list_of_speakers;
|
||||
tag_ids: tag[];
|
||||
attachment_ids: mediafile[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_poll {
|
||||
id: number;
|
||||
pollmethod: string;
|
||||
state: number;
|
||||
type: string;
|
||||
title: string;
|
||||
onehundred_percent_base: string;
|
||||
majority_method: string;
|
||||
votesvalid: decimal(6);
|
||||
votesinvalid: decimal(6);
|
||||
votescast: decimal(6);
|
||||
|
||||
option_ids: motion_option[];
|
||||
motion_id: motion;
|
||||
voted_ids: user[];
|
||||
group_ids: group[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_option {
|
||||
id: number;
|
||||
yes: decimal(6);
|
||||
no: decimal(6);
|
||||
abstain: decimal(6);
|
||||
|
||||
vote_ids: motion_vote[];
|
||||
}
|
||||
Interface motion_vote {
|
||||
id: number;
|
||||
weight: decimal(6);
|
||||
value: string;
|
||||
|
||||
option_id: motion_option;
|
||||
user_id: user;
|
||||
}
|
||||
Interface motion_submitter {
|
||||
id: number;
|
||||
weight: number;
|
||||
|
||||
user_id: user;
|
||||
motion_id: motion;
|
||||
}
|
||||
Interface motion_comment {
|
||||
id: number;
|
||||
comment: HTML;
|
||||
|
||||
motion_id: motion;
|
||||
section_id: motion_comment_section;
|
||||
}
|
||||
Inteface motion_comment_section {
|
||||
id: number;
|
||||
name: string;
|
||||
weight: number;
|
||||
|
||||
read_group_ids: group[];
|
||||
write_group_ids: group[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_category {
|
||||
id: number;
|
||||
name: string;
|
||||
prefix: string;
|
||||
weight: number;
|
||||
level: number;
|
||||
|
||||
parent_id: motion_category;
|
||||
children_ids: motion_category[];
|
||||
motion_ids: motion[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_block {
|
||||
id: number;
|
||||
title: string;
|
||||
internal: boolean;
|
||||
|
||||
motion_ids: motion[];
|
||||
agenda_item_id: agenda_item;
|
||||
list_of_speakers_id: list_of_speakers;
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_change_recommendation {
|
||||
id: number;
|
||||
rejected: boolean;
|
||||
internal: boolean;
|
||||
type: number;
|
||||
other_description: string;
|
||||
line_from: number;
|
||||
line_to: number;
|
||||
text: HTML;
|
||||
creation_time: datetime;
|
||||
|
||||
motion_id: motion;
|
||||
}
|
||||
Interface motion_state {
|
||||
id: number;
|
||||
name: string;
|
||||
recommendation_label: string;
|
||||
css_class: string;
|
||||
restrictions: string[],
|
||||
allow_support: boolean;
|
||||
allow_create_poll: boolean;
|
||||
allow_submitter_edit: boolean;
|
||||
set_identifier: boolean;
|
||||
show_state_extension_field: boolean;
|
||||
merge_amendment_into_final: number;
|
||||
show_recommendation_extension_field: boolean;
|
||||
|
||||
next_state_ids: motion_state[];
|
||||
previous_state_ids: motion_state[];
|
||||
motion_ids: motion[];
|
||||
motion_recommendation_ids: motion[];
|
||||
workflow_id: motion_workflow;
|
||||
first_state_of_workflow_id: motion_workflow;
|
||||
}
|
||||
Interface motion_workflow {
|
||||
id: number;
|
||||
name: string;
|
||||
|
||||
state_ids: motion_state[];
|
||||
first_state_id: motion_state;
|
||||
motion_ids: motion[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface motion_statute_paragraph {
|
||||
id: number;
|
||||
title: string;
|
||||
text: HTML;
|
||||
weight: number;
|
||||
|
||||
motion_ids: motion[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface assignment {
|
||||
id: number;
|
||||
title: string;
|
||||
description: HTML;
|
||||
open_posts: number;
|
||||
phase: number;
|
||||
poll_description_default: string;
|
||||
|
||||
assignment_related_user_ids: assignment_related_user[];
|
||||
poll_ids: assignment_poll[];
|
||||
agenda_item_id: agenda_item;
|
||||
list_of_speakers_id: list_of_speakers;
|
||||
tag_ids: tag[];
|
||||
attachment_ids: mediafile[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Inteface assignment_related_user {
|
||||
id: number;
|
||||
elected: boolean;
|
||||
weight: number;
|
||||
|
||||
assignment_id: assignment;
|
||||
user_id: user;
|
||||
}
|
||||
Interface assignment_poll {
|
||||
id: number;
|
||||
allow_multiple_votes_per_candidate: boolean;
|
||||
global_abstain: boolean;
|
||||
global_no: boolean;
|
||||
amount_global_abstain: decimal(6);
|
||||
amount_global_no: decimal(6);
|
||||
pollmethod: string;
|
||||
state: number;
|
||||
title: string;
|
||||
description: string;
|
||||
type: string;
|
||||
onehundred_percent_base: string;
|
||||
majority_method: string;
|
||||
votes_amount: number;
|
||||
votescast: decimal(6);
|
||||
votesinvalid: decimal(6);
|
||||
votesvalid: decimal(6);
|
||||
|
||||
assignment_id: assignment;
|
||||
voted_ids: user[];
|
||||
group_ids: group[];
|
||||
option_ids: assignment_option[];
|
||||
meeting_id: meeting;
|
||||
}
|
||||
Interface assignment_option {
|
||||
id: number;
|
||||
yes: decimal(6);
|
||||
no: decimal(6);
|
||||
abstain: decimal(6);
|
||||
weight: number;
|
||||
|
||||
poll_id: assignment_poll;
|
||||
user_id: user;
|
||||
}
|
||||
Interface assignment_vote {
|
||||
id: number;
|
||||
value: string;
|
||||
weight: decimal(6);
|
||||
|
||||
option_id: assignment_option;
|
||||
user_id: user;
|
||||
}
|
||||
|
||||
// New models
|
||||
Interface meeting {
|
||||
id: number;
|
||||
identifier: string; // For unique urls.
|
||||
is_template: boolean; // Unique within a committee
|
||||
enable_anonymous: boolean;
|
||||
|
||||
// Old "general_*" configs
|
||||
name: string;
|
||||
description: string;
|
||||
location: string;
|
||||
start_time: datetime;
|
||||
end_time: datetime;
|
||||
welcome_title: string;
|
||||
welcome_text: HTML;
|
||||
|
||||
// Export section still needed?
|
||||
// Or should this be moved into committee-scope or organisation-scope?
|
||||
export_csv_encoding: string;
|
||||
export_csv_separator: string;
|
||||
export_pdf_pagenumber_alignment: string;
|
||||
export pdf_fontsize: number;
|
||||
export_pdf_pagesize: string;
|
||||
|
||||
// TODO: custom translations
|
||||
// TODO: @emanuel: Are they meeting-specific, organsation-wide or should
|
||||
// both have custom translation?
|
||||
|
||||
// Is this right here in a meeting?
|
||||
users_sort_by: string;
|
||||
users_enable_presence_view: boolean;
|
||||
|
||||
// Motions
|
||||
motions_default_workflow: workflow; // TODO: relation
|
||||
motions_default_statute_amendments_workflow: workflow; // TODO: relation
|
||||
motions_preamble: string;
|
||||
motions_default_line_numbering: string;
|
||||
motions_line_length: number;
|
||||
motions_reason_required: boolean;
|
||||
motions_enable_text_on_projector: boolean;
|
||||
motions_enable_reason_on_projector: boolean;
|
||||
motions_enable_sidebox_on_projector: boolean;
|
||||
motions_enable_resommendation_on_projector: boolean;
|
||||
motions_show_referring_motions: boolean;
|
||||
motions_show_sequential_number: boolean;
|
||||
motions_recommendations_by: string;
|
||||
motions_statute_recommendations_by: string;
|
||||
motions_recommendation_text_mode: string;
|
||||
motions_default_sorting: string;
|
||||
motions_identifier_type: string;
|
||||
motions_identifier_min_digits: number;
|
||||
motions_identifier_with_blank: boolean;
|
||||
motions_statutes_enabled: boolean;
|
||||
motions_amendments_enabled: boolean;
|
||||
motions_amendments_in_main_list: boolean;
|
||||
motions_amendments_prefix: string;
|
||||
motions_amendments_text_mode: string;
|
||||
motions_amendments_multiple_paragraphs: boolean;
|
||||
motions_supporters_min_amount: number;
|
||||
motions_supporters_enable_autoremove: boolean;
|
||||
motions_export_title: string;
|
||||
motions_export_preamble: string;
|
||||
motions_export_submitter_recommendation: boolean;
|
||||
motions_export follow_recommendation: boolean;
|
||||
|
||||
// Assignments
|
||||
assignments_poll_add_candidates_to_list_of_spekaers: boolean;
|
||||
assignemnts_export_pdf_title: string;
|
||||
assignments_export_pdf_preamble: string;
|
||||
|
||||
projector_ids: projector[];
|
||||
projectiondefault_ids: projectiondefault[];
|
||||
projector_countdown_ids: projector_countdown[];
|
||||
projector_message_ids: projector_message[];
|
||||
tag_ids: tag[];
|
||||
agenda_item_ids: agenda_item[];
|
||||
list_of_speakers_ids: list_of_speakers[];
|
||||
topic_ids: topic[];
|
||||
group_ids: group[];
|
||||
personal_note_ids: personal_note[];
|
||||
mediafile_ids: mediafile[];
|
||||
motion_ids: motion[];
|
||||
motion_poll_ids: motion_poll[];
|
||||
motion_comment_section_ids: motion_comment_section[];
|
||||
motion_category_ids: motion_category[];
|
||||
motion_block_ids: motion_block[];
|
||||
motion_workflow_ids: motion_workflow[];
|
||||
motion_statute_paragraph_ids: motion_statute_paragraph[];
|
||||
assignment_ids: assignment[];
|
||||
assignment_poll_ids: assignment_poll[];
|
||||
|
||||
// No relations to a meeting:
|
||||
// user; OK, because not meeting-specific
|
||||
// projection
|
||||
// speaker
|
||||
// motion_option
|
||||
// motion_vote
|
||||
// motion_comment
|
||||
// motion_submitter
|
||||
// motion_change_recommendation
|
||||
// motion_state
|
||||
// assignment_related_user
|
||||
// assignment_option
|
||||
// assignment_vote
|
||||
|
||||
// Why: These are mostly M2M models or ones, that will never have a list view.
|
||||
// There would be no need to link them to the meeting, if they can be
|
||||
// reached through a parent model. E.g. a motion_option can be reached through
|
||||
// a motion_poll. There will never be the need to make something like "show all
|
||||
// motion_options at once".
|
||||
// TODO: Is this right for all above stated models?
|
||||
// TODO: We might link user to a meeting. A member is defined by checking,
|
||||
// if a user is assigned to at least one group. This "query" must be checked,
|
||||
// if it can be performed.
|
||||
|
||||
present_user_ids: user[]; // Link to user/is_present_in_meeting_ids
|
||||
resource_ids: resource[];
|
||||
}
|
||||
Interface committee {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string; // TODO: @emanuel Or HTML? Or not needed (-> UI decision)
|
||||
|
||||
meeting_ids: meeting[];
|
||||
member_ids: user[];
|
||||
manager_ids: user[];
|
||||
forward_to_committee_ids: committee[];
|
||||
received_forwardings_from_committee_ids: committee[];
|
||||
organisation_id: organisation;
|
||||
}
|
||||
Interface organisation {
|
||||
id: number;
|
||||
name: string;
|
||||
description: HTML; // TODO: @emanuel Needed??
|
||||
|
||||
// Configs:
|
||||
legal_notice: string;
|
||||
privacy_policy: string;
|
||||
login_text: string;
|
||||
theme: string;
|
||||
|
||||
// TODO: OS3 user configs (export, email, ...)
|
||||
|
||||
committee_ids: committee[];
|
||||
role_ids: role[];
|
||||
resource_ids: resource[];
|
||||
}
|
||||
Interface role {
|
||||
id: number;
|
||||
name: string;
|
||||
permissions: string[]; // 'can_manage_committees', 'can_manage_users', TODO: more permissions
|
||||
is_superadmin_role: boolean;
|
||||
orginasation_id: number;
|
||||
user_ids: user[];
|
||||
}
|
Loading…
Reference in New Issue
Block a user