openapi: 3.0.3

info:
  version: "3.2.4"
  title: CF Online
  description: CF Online
  license:
    name: Artistic License 2.0
    url: https://www.perlfoundation.org/artistic-license-20.html
  contact:
    name: Andrej Ramašeuski
    email: andrej.ramaseuski@pirati.cz
    url: https://pardubicky.pirati.cz/lide/andrej-ramaseuski/

servers:
    - url: https://cf2021.pirati.cz/api
      description: Production server
    - url: https://cf2021.pir-test.eu/api
      description: Developement server
    - url: http://127.0.0.1:3000/api
      description: Local server

components:
  securitySchemes:
    Bearer:
     name: Authorization
     in: header
     type: apiKey
  parameters:
    offset:
      name: offset
      in: query
      description: The number of items to skip before starting to collect the result set
      required: false
      schema:
        type: integer
        default: 0
        minimum: 0
    limit:
      name: limit
      in: query
      description: The numbers of items to return
      required: false
      schema:
        type: integer
        default: 100
        minimum: 1
  schemas:
    Announcement:
      type: object
      description: Notifikace
      properties:
        id:
          type: integer
          readOnly: true
        datetime:
          type: string
          readOnly: true
        type:
          type: integer
          enum: [0, 1, 2, 3, 4, 5]
        content:
          type: string
          maxLength: 1024
        link:
          type: string
          maxLength: 256
        related_post_id:
          type: integer
    ConfigEntry:
      type: object
      properties:
        id:
          type: string
          readOnly: true
        is_readonly:
          type: boolean
          readOnly: true
        value:
          type: string
    Event:
      type: object
      description: Udalost
      properties:
        id:
          type: integer
          readOnly: true
        type:
          type: integer
          enum: [1, 2, 3]
        state:
          type: integer
          enum: [0, 1, 2]
        is_opened:
          type: boolean
        is_published:
          type: boolean
        start:
          type: string
          maxLength: 20
        finish:
          type: string
          maxLength: 20
          nullable: true
        name:
          type: string
        description:
          type: string
        organizer:
          type: string
        stream_url:
          type: string
          nullable: true
        meet_url:
          type: string
          readOnly: true
          nullable: true
        record_url:
          type: string
          readOnly: true
          nullable: true
        acl:
           type: array
           items:
              $ref: '#/components/schemas/EventRole'
    EventInList:
      type: object
      description: Udalost
      properties:
        id:
          type: integer
          readOnly: true
        type:
          type: integer
          enum: [1, 2, 3]
        state:
          type: integer
          enum: [0, 1, 2]
        is_published:
          type: boolean
        is_editable:
          type: boolean
        is_deletable:
          type: boolean
        start:
          type: string
          maxLength: 20
        finish:
          type: string
          maxLength: 20
          nullable: true
        name:
          type: string
        description:
          type: string
        organizer:
          type: string
        stream_url:
          type: string
          nullable: true
        banner:
          type: string
          nullable: true
    EventRole:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        subject:
          type: string
        class:
          type: string
          enum: ['user', 'group']
        role:
          type: string
          enum: ['chairmain', 'member', 'guest']
    Option:
      type: object
      properties:
        class:
          type: string
        value:
          type: string
        label:
          type: string
    Post:
      type: object
      description: Prispevek
      properties:
        id:
          type: integer
          readOnly: true
        datetime:
          type: string
          readOnly: true
        type:
          type: integer
          enum: [0, 1]
        state:
          type: integer
          enum: [0, 1, 2, 3, 4]
        content:
          type: string
          maxLength: 1024
        is_changed:
          type: boolean
        is_archived:
          type: boolean
        author:
            $ref: '#/components/schemas/User'
        ranking:
            $ref: '#/components/schemas/Ranking'
        history_log:
           type: array
           items:
              $ref: '#/components/schemas/PostHistoryItem'
    PostHistoryItem:
      type: object
      properties:
        attribute:
          type: string
        value:
          type: string
        datetime:
          type: string
        originator:
          type: string
    ProgramScheduleEntry:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        number:
          type: string
          nullable: true
        is_live:
          type: boolean
        discussion_opened:
          type: boolean
        title:
          type: string
        proposer:
          type: string
          nullable: true
        speakers:
          type: string
          nullable: true
        vote:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        expected_start_at:
          type: string
        expected_finish_at:
          type: string
          nullable: true
    Ranking:
      type: object
      properties:
        score:
          type: integer
        likes:
          type: integer
        dislikes:
          type: integer
        my_vote:
          type: integer
    User:
      type: object
      properties:
        id:
            type: integer
        name:
            type: string
        group:
            type: string
        username:
            type: string
        secret:
            type: string
        jitsi_url:
            type: string
            nullable: true
        is_banned:
            type: boolean

paths:
  /config:
    get:
      x-mojo-to: config#entries
      tags:
        - config
      summary: "Konfigurace systemu"
      operationId: getConfig
      responses:
        200:
          description: Konfigurace systemu
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ConfigEntry'
  /config/{id}:
    put:
      x-mojo-to: config#update
      security:
        - Bearer: ['chairman']
      tags:
        - config
      summary: "Upravit polozku konfigu"
      operationId: updateConfigEntry
      parameters:
        - name: id
          description: "ID"
          in: path
          schema:
            type: integer
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigEntry'
      responses:
        204:
          description: Program entry updated

  /events:
    post:
      x-mojo-to: events#create
      security:
        - Bearer: ['organizer']
      tags:
        - events
      summary: "Pridat udalost"
      operationId: createEvent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: integer
                  enum: [1, 2, 3]
                  example: 1
                is_opened:
                  type: boolean
                  example: true
                start:
                  type: string
                  maxLength: 20
                  example: '18.07.2021 10:00'
                finish:
                  type: string
                  maxLength: 20
                  example: '18.07.2021 18:00'
                name:
                  type: string
                  maxLength: 256
                  example: 'Schůze KS Pardubický kraj'
                description:
                  type: string
                  maxLength: 1024
                  example: ''
                organizer:
                  type: string
                  maxLength: 256
                  example: 'PKS Pardubický kraj'
              required:
                - type
                - start
                - name
      responses:
        201:
          description: Event created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    description: Event id
    get:
      x-mojo-to: events#list
      security:
        - Bearer: ['optional', '*']
      tags:
        - events
      summary: "Udalosti"
      operationId: getEvents
      parameters:
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - name: type
        in: query
        description: "Typ udalosti"
        required: false
        schema:
          type: integer
          enum: [1, 2, 3]
      - name: show_finished
        in: query
        description: "Zobrazovat ukoncene"
        required: false
        schema:
          type: boolean
          default: false
        example: true
      - name: sort
        description: "Razeni"
        in: query
        style: form
        schema:
          type: array
          uniqueItems: true
          items:
            type: string
            enum: [ start, -start]
          default: [ start ]
      responses:
        200:
          description: Events
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                    description: Celkovy pocet
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/EventInList'
  /events/{id}:
    get:
      x-mojo-to: events#get
      security:
        - Bearer: ['optional', '*']
      tags:
        - events
      summary: "Detail udalosti"
      operationId: getEvent
      parameters:
      - name: id
        in: path
        required: true
        example: 100345
        description: "ID"
        schema:
          type: integer
      responses:
        200:
          description: Udalost
          content:
            application/json:
              schema:
                  $ref: '#/components/schemas/Event'
    put:
      x-mojo-to: events#update
      security:
        - Bearer: []
      tags:
        - events
      summary: "Editace udalosti"
      operationId: updateEvent
      parameters:
      - name: id
        in: path
        required: true
        example: 100345
        description: "Event ID"
        schema:
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: integer
                  enum: [1, 2, 3]
                is_opened:
                  type: boolean
                  example: true
                state:
                  type: integer
                  enum: [0, 1, 2]
                is_published:
                  type: boolean
                start:
                  type: string
                  maxLength: 20
                  example: '18.07.2021 10:00'
                finish:
                  type: string
                  maxLength: 20
                  example: '18.07.2021 18:00'
                name:
                  type: string
                  maxLength: 256
                  example: 'Schůze KS Pardubický kraj'
                description:
                  type: string
                  maxLength: 1024
                  example: ''
                organizer:
                  type: string
                  maxLength: 256
                  example: 'PKS Pardubický kraj'
      responses:
        204:
          description: Event updated

    delete:
      x-mojo-to: events#delete
      security:
        - Bearer: ['organizer']
      tags:
        - events
      summary: "Smazat udalost"
      operationId: deleteEvent
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      responses:
        204:
          description: Event deleted

  /events/{id}/roles:
    post:
      x-mojo-to: events#role_add
      security:
        - Bearer: ['organizer']
      tags:
        - events
      summary: "Priradit roli pro udalost"
      operationId: addEventRole
      parameters:
      - name: id
        in: path
        required: true
        example: 100345
        description: "Event ID"
        schema:
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                subject_class:
                  type: string
                  enum: ['user', 'group']
                  example: 'user'
                subject_value:
                  type: string
                  example: 'cen:f'
                subject_label:
                  type: string
                  example: 'Celostátní fórum'
                role:
                  type: string
                  enum: ['chairman', 'member', 'guest', 'jitsi']
                  example: 'member'
              required:
                - subject_class
                - subject_value
                - role
      responses:
        201:
          description: ACL record created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    description: ACL record id
    delete:
      x-mojo-to: events#role_delete
      security:
        - Bearer: ['*']
      tags:
        - events
      summary: "Odebrat roli pro udalost"
      operationId: deleteEventRole
      parameters:
      - name: id
        in: path
        required: true
        example: 100345
        description: "Event ID"
        schema:
          type: integer
      - name: role_id
        in: query
        required: true
        example: 200345
        description: "Identifikator ACL zaznamu"
        schema:
          type: integer
      responses:
        204:
          description: Role deleted

  /events/{id}/banner:
    post:
      x-mojo-to: events#banner
      security:
        - Bearer: ['*']
      tags:
        - events
      summary: "Uploadovat banner"
      operationId: addEventBanner
      parameters:
      - name: id
        in: path
        required: true
        example: 100345
        description: "Event ID"
        schema:
          type: integer
      requestBody:
        content:
          application/octet-stream:
            schema:
              # a binary file of any type
              type: string
              format: binary
      responses:
        201:
          description: Banner uploaded

  /sso/subjects:
    get:
      x-mojo-to: SSO#subjects
      tags:
        - sso
      summary: "Subjekty SSO"
      operationId: getSubjects
      parameters:
      - name: search
        in: query
        description: "Retezec pro vyhledavani"
        required: true
        schema:
          type: string
          minLength: 3
          pattern: '^[\w:\.\-]{3,}$'
          example: 'cen:'
      - name: class
        in: query
        description: "Trida subjektu"
        required: true
        schema:
          type: string
          enum: [all, user, group]
          example: group
          default: all
      responses:
        200:
          description: Seznam subjektu
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Option'

  /program:
    get:
      x-mojo-to: program#entries
      tags:
        - programm
      summary: "Program zasedani"
      operationId: getProgram
      responses:
        200:
          description: Program zasedani
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ProgramScheduleEntry'

  /program/{id}:
    put:
      x-mojo-to: program#update
      security:
        - Bearer: ['chairman']
      tags:
        - programm
      summary: "Upravit bod programu"
      operationId: updateProgramEntry
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProgramScheduleEntry'
      responses:
        204:
          description: Program entry updated

  /announcements:
    post:
      x-mojo-to: announcements#create
      security:
        - Bearer: ['chairman']
      tags:
        - announcements
      summary: "Pridat notifikaci"
      operationId: createAnnouncement
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: integer
                  enum: [3, 4]
                content:
                  type: string
                  maxLength: 1024
                link:
                  type: string
                  maxLength: 256
              required:
                - content
      responses:
        201:
          description: Announcement created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    description: Announcement id
    get:
      x-mojo-to: announcements#list
      tags:
        - announcements
      summary: "Seznam notifikaci"
      operationId: getAnnouncements
      parameters:
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - name: sort
        description: "Razeni"
        in: query
        style: form
        schema:
          type: array
          uniqueItems: true
          items:
            type: string
            enum: [ datetime, -datetime]
          default: [ -datetime ]
      responses:
        200:
          description: Seznam motifikaci
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                    description: Celkovy pocet
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Announcement'

  /announcements/{id}:
    put:
      x-mojo-to: announcements#update
      security:
        - Bearer: ['chairman']
      tags:
        - announcements
      summary: "Upravit notifikaci"
      operationId: updateAnnouncement
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Announcement'
      responses:
        204:
          description: Announcement updated
    delete:
      x-mojo-to: announcements#delete
      security:
        - Bearer: ['chairman']
      tags:
        - announcements
      summary: "Smazat notifikaci"
      operationId: deleteAnnouncement
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      responses:
        204:
          description: Announcement deleted

  /posts:
    post:
      x-mojo-to: posts#create
      security:
        - Bearer: ['member', 'regp']
      tags:
        - posts
      summary: "Pridat zpravu"
      operationId: createPost
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: integer
                  enum: [0, 1]
                content:
                  type: string
                  maxLength: 1024
              required:
                - type
                - content
      responses:
        201:
          description: Post created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    description: Post id
    get:
      x-mojo-to: posts#list
      security:
        - Bearer: ['optional', 'member', 'regp']
      tags:
        - posts
      summary: "Zpravy"
      operationId: getPosts
      parameters:
      - $ref: '#/components/parameters/offset'
      - $ref: '#/components/parameters/limit'
      - name: type
        in: query
        description: "Typ zpravy"
        required: false
        schema:
          type: integer
          enum: [0, 1]
      - name: program_entry_id
        in: query
        description: "Identifikator bodu programu"
        required: false
        schema:
          type: integer
      - name: archived
        in: query
        description: "Zobrazovat archivovane"
        required: false
        schema:
          type: boolean
      - name: sort
        description: "Razeni"
        in: query
        style: form
        schema:
          type: array
          uniqueItems: true
          items:
            type: string
            enum: [ type, datetime, -type, -datetime]
          default: [ -datetime ]
      responses:
        200:
          description: Posts
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                    description: Celkovy pocet
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Post'
  /posts/{id}:
    get:
      x-mojo-to: posts#get
      security:
        - Bearer: ['optional', 'member', 'regp']
      tags:
        - posts
      summary: "Detail zpravy"
      operationId: getPost
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      responses:
        200:
          description: Post
          content:
            application/json:
              schema:
                  $ref: '#/components/schemas/Post'
    put:
      x-mojo-to: posts#update
      security:
        - Bearer: ['member', 'regp']
      tags:
        - posts
      summary: "Uprava zpravu"
      operationId: updatePost
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                state:
                  type: integer
                  enum: [0, 1, 2, 3, 4]
                content:
                  type: string
                  maxLength: 1024
                is_archived:
                  type: boolean
      responses:
        204:
          description: Post updated

    delete:
      x-mojo-to: posts#delete
      security:
        - Bearer: ['chairman']
      tags:
        - posts
      summary: "Smazat zpravu"
      operationId: deletePost
      parameters:
      - name: id
        in: path
        required: true
        description: "ID"
        schema:
          type: integer
      responses:
        204:
          description: Post deleted

  /posts/{id}/like:
    patch:
      security:
        - Bearer: ['member', 'regp']
      x-mojo-to: posts#ranking
      tags:
        - posts
      summary: "Like"
      operationId: likePost
      parameters:
      - name: id
        in: path
        description: "ID"
        required: true
        schema:
          type: integer
      - name: ranking
        in: query
        required: false
        schema:
          type: integer
          enum: [1]
          default: 1
      responses:
        204:
          description: Post liked

  /posts/{id}/dislike:
    patch:
      security:
        - Bearer: ['member', 'regp']
      x-mojo-to: posts#ranking
      tags:
        - posts
      summary: "Like"
      operationId: dislikePost
      parameters:
      - name: id
        in: path
        description: "ID"
        schema:
          type: integer
        required: true
      - name: ranking
        in: query
        required: false
        schema:
          type: integer
          enum: [-1]
          default: -1
      responses:
        204:
          description: Post disliked

  /users/me:
    get:
      x-mojo-to: users#me
      security:
        - Bearer: []
      tags:
        - users
      summary: "Detail uzivatele"
      operationId: getCurrentUser
      responses:
        200:
          description: User
          content:
            application/json:
              schema:
                  $ref: '#/components/schemas/User'

  /users/{id}/ban:
    patch:
      security:
        - Bearer: ['chairman']
      x-mojo-to: users#ban
      tags:
        - users
      summary: Ban user
      operationId: banUser
      parameters:
      - name: id
        in: path
        description: "ID"
        schema:
          type: integer
        required: true
      responses:
        204:
          description: User banned

  /users/{id}/unban:
    patch:
      security:
        - Bearer: ['chairman']
      x-mojo-to: users#unban
      tags:
        - users
      summary: Unban user
      operationId: UnbanUser
      parameters:
      - name: id
        in: path
        description: "ID"
        required: true
        schema:
          type: integer
      responses:
        204:
          description: User banned

  /users/{id}/jitsi:
    patch:
      security:
        - Bearer: ['chairman']
      x-mojo-to: users#jitsi
      tags:
        - users
      summary: Set jitsi access
      operationId: jitsi
      parameters:
        - name: id
          description: "ID"
          in: path
          schema:
            type: integer
          required: true
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                allowed:
                  type: boolean
      responses:
        204:
          description: Status changed

  /jitsi/url:
    post:
      x-mojo-to: jitsi#url
      security:
        - Bearer: ['chairman']
      tags:
        - jitsi
      summary: "Vygenerovat odkaz pro jitsi"
      operationId: jitsiUrl
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                avatar:
                  type: string
                room:
                  type: string
                token_lifetime:
                  type: integer
              required:
                - name
      responses:
        200:
          description: Jitsi url
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                    description: Jitsi meet url
