Types: Nativ: null, string, number, JSON Fqid: Strukturierter string HTML: string mit HTML Inhalt []: Array von Typ T : 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_` do have values for `` 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 guest_meeting_ids: meeting[]; // Links to meeting/guest_ids // 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__ids: group[]; personal_note__ids: personal_note[]; projection__ids: projection[]; supported_motion__ids: motion[]; submitted_motion__ids: motion_submitter[]; assignment_related_user__ids: assignment_related_user[]; motion_vote__ids: motion_vote[]; assignment_vote__ids: assignment_vote[]; motion_voted_poll__ids: motion_poll[]; assignment_voted_poll__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//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 `/resource/` 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_: 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; // Note: The related motions may not be in the same meeting derived_motion_ids: motion[]; // Note: The related motions may not be in the same meeting 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? // TODO: @emanuel 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. // Other relations resource_ids: resource[]; // Links to resource/meeting_id committee_id: committee; // Links to committee/meeting_ids default_meeting_for_committee_id: committee; // Links to committee/default_meeting_id present_user_ids: user[]; // Links to user/is_present_in_meeting_ids guest_ids: user[]; // Links to users/guest_meeting_ids temorary_user_ids: user[]; // Links to user/meeting_id } Interface committee { id: number; name: string; description: string; // TODO: @emanuel Or HTML? Or not needed (-> UI decision) meeting_ids: meeting[]; default_meting_id: 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[]; }