# NOTE: Do not upgrade past Swagger 2. zclient does not support OpenAPI 3 unless
# https://github.com/Yelp/bravado/issues/306 is resolved.
swagger: "2.0"
info:
  title: "user"
  description: "API for managing users and groups."
  version: "1.5.0"
  contact:
    name: "Maestro"
    email: "maestro-dev@zoox.com"
    url: "https://git.zooxlabs.com/zooxco/driving"
basePath: "/v1/"
schemes: ["http"]
paths:
  /users/:
    get:
      summary: "Find users."
      operationId: "findUsers"
      produces: ["application/json"]
      parameters:
        - $ref: "#/parameters/UserIdsQuery"
        - $ref: "#/parameters/UserEmailQuery"
        - $ref: "#/parameters/Limit"
        - $ref: "#/parameters/Offset"
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/UserList"
        "400": { $ref: "#/responses/BadRequest" }
        "500": { $ref: "#/responses/InternalServerError" }
    post:
      summary: "Create user."
      # TODO: ? Rename this operation to "createUser" in next major revision?
      operationId: "addUser"
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: user
          in: body
          description: "Created user."
          required: true
          schema:
            $ref: "#/definitions/User"
      responses:
        "201":
          description: "Resource was successfully created."
          schema:
            $ref: "#/definitions/User"
        "400": { $ref: "#/responses/BadRequest" }
        "409": { $ref: "#/responses/Conflict" }
        "500": { $ref: "#/responses/InternalServerError" }
  /users/{userId}:
    parameters:
      - $ref: "#/parameters/UserId"
    get:
      summary: "Get user."
      operationId: "getUser"
      produces: ["application/json"]
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/User"
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "500": { $ref: "#/responses/InternalServerError" }
    put:
      summary: "Update user."
      operationId: "updateUser"
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: user
          in: body
          description: "Updated user."
          required: true
          schema:
            $ref: "#/definitions/User"
      responses:
        "200":
          description: "Resource was successfully updated."
          schema:
            $ref: "#/definitions/User"
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "409": { $ref: "#/responses/Conflict" }
        "500": { $ref: "#/responses/InternalServerError" }
    delete:
      summary: "Delete user."
      operationId: "deleteUser"
      produces: ["application/json"]
      responses:
        "204": { $ref: "#/responses/NoContent" }
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "500": { $ref: "#/responses/InternalServerError" }
  /groups/:
    get:
      summary: "Find groups."
      operationId: "findGroups"
      produces: ["application/json"]
      parameters:
        - $ref: "#/parameters/GroupIdsQuery"
        - $ref: "#/parameters/GroupNameQuery"
        - $ref: "#/parameters/GroupDescriptionQuery"
        - $ref: "#/parameters/Limit"
        - $ref: "#/parameters/Offset"
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/GroupList"
        "400": { $ref: "#/responses/BadRequest" }
        "500": { $ref: "#/responses/InternalServerError" }
    post:
      summary: "Create group."
      operationId: "createGroup"
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: group
          in: body
          description: "Created group."
          required: true
          schema:
            $ref: "#/definitions/Group"
      responses:
        "201":
          description: "Resource was successfully created."
          schema:
            $ref: "#/definitions/Group"
        "400": { $ref: "#/responses/BadRequest" }
        "409": { $ref: "#/responses/Conflict" }
        "500": { $ref: "#/responses/InternalServerError" }
  /groups/{groupId}:
    parameters:
      - $ref: "#/parameters/GroupId"
    get:
      summary: "Get group."
      operationId: "getGroup"
      produces: ["application/json"]
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/Group"
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "500": { $ref: "#/responses/InternalServerError" }
    put:
      summary: "Update group."
      operationId: "updateGroup"
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: group
          in: body
          description: "Updated group."
          required: true
          schema:
            $ref: "#/definitions/Group"
      responses:
        "200":
          description: "Resource was successfully updated."
          schema:
            $ref: "#/definitions/Group"
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "409": { $ref: "#/responses/Conflict" }
        "500": { $ref: "#/responses/InternalServerError" }
    delete:
      summary: "Delete group."
      operationId: "deleteGroup"
      produces: ["application/json"]
      responses:
        "204": { $ref: "#/responses/NoContent" }
        "400": { $ref: "#/responses/BadRequest" }
        "404": { $ref: "#/responses/NotFound" }
        "500": { $ref: "#/responses/InternalServerError" }

  /auth_groups/:
    get:
      summary: "Get auth groups"
      operationId: "getAuthGroups"
      produces:
        - application/json
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/AuthGroupResponse"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"

  /auth_groups/{auth_group_id}:
    get:
      summary: "Get auth group"
      operationId: "getAuthGroupById"
      parameters:
        - $ref: "#/parameters/AuthGroupId"
      produces:
        - application/json
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/AuthGroup"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"
    put:
      summary: "Update an auth group"
      operationId: "updateAuthGroup"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - $ref: "#/parameters/AuthGroupId"
        - in: "body"
          name: "auth_group_update"
          schema:
            $ref: "#/definitions/AuthGroupUpdate"
          required: true
      responses:
        "200":
          description: "Updating auth group was successful"
          schema:
            $ref: "#/definitions/AuthGroup"
        "201":
          description: "Creating auth group was successful"
          schema:
            $ref: "#/definitions/AuthGroup"
        "400":
          description: "Invalid data is provided"
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Some internal server error has occurred so retry it again"
          schema:
            $ref: "#/definitions/ErrorInfo"
    delete:
      summary: "Delete an auth group"
      operationId: "deleteAuthGroup"
      parameters:
        - $ref: "#/parameters/AuthGroupId"
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"

  /ride_services/:
    get:
      summary: "Get ride services"
      operationId: "getRideServices"
      parameters:
        - in: query
          name: auth_groups
          description: "A list of auth group name from Auth0"
          type: "array"
          items:
            type: "string"
            format: "uuid"
        - in: query
          name: email
          description: "email of the user"
          type: "string"
      produces:
        - application/json
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/RideServicesResponse"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"
    post:
      summary: "Create a new ride service"
      operationId: "createRideService"
      consumes:
        - application/json
      produces:
        - application/json
      parameters:
        - name: ride_service
          in: body
          description: "New ride service"
          required: true
          schema:
            $ref: "#/definitions/RideService"
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/RideService"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"

  /ride_services/{ride_service_id}:
    get:
      summary: "Get a ride service"
      operationId: "getRideServiceById"
      parameters:
        - $ref: "#/parameters/RideServiceId"
      produces:
        - application/json
      responses:
        "200":
          description: "Operation was successful"
          schema:
            $ref: "#/definitions/RideService"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"
    put:
      summary: "Update the ride service"
      operationId: "updateRideService"
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - $ref: "#/parameters/RideServiceId"
        - in: "body"
          name: "ride_service"
          schema:
            $ref: "#/definitions/RideService"
          required: true
      responses:
        "200":
          description: "Operation was successful"
          schema:
            $ref: "#/definitions/RideService"
        "400":
          description: "Invalid data is provided"
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Some internal server error has occurred so retry it again"
          schema:
            $ref: "#/definitions/ErrorInfo"
    delete:
      summary: "Delete a ride service"
      operationId: "deleteRideService"
      parameters:
        - $ref: "#/parameters/RideServiceId"
      responses:
        "200":
          description: "Operation was successful."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "400":
          description: "Invalid parameter was provided."
          schema:
            $ref: "#/definitions/ErrorInfo"
        "500":
          description: "Unknown internal error."
          schema:
            $ref: "#/definitions/ErrorInfo"

definitions:
  User:
    description: "A Maestro user."
    type: "object"
    properties:
      id:
        description: "Universally-unique identifier string."
        type: "string"
        format: "uuid"
        readOnly: true
      email:
        description: "Email address of the user."
        type: "string"
        format: "email"
      firstName:
        description: "First name of the user."
        type: "string"
      lastName:
        description: "Last name of the user."
        type: "string"
      phoneNumber:
        description: "Phone number of the user."
        type: "string"
      userConfig:
        $ref: "#/definitions/UserConfig"
      groups:
        description: "Groups for which the user is a member. For requests, only the IDs will be honored."
        type: "array"
        items:
          $ref: "#/definitions/Group"
      ride_service_ids:
        type: array
        items:
          type: string
          format: uuid
          description: a list of ride service ids
    # required for REQUESTS ONLY: email, firstName
    # required for RESPONSES ONLY: id
    additionalProperties: false
  UserConfig:
    type: "object"
    description: "User-specific configuration related to the client/app."
    properties:
      hailMode:
        type: "string"
        description: "The type of hailing flow that will be shown to the user."
        enum:
          - P2P
          - CONTINUOUS
          - FIXED
          - VH6_DEMO_CHESS
      preferredPickup:
        $ref: "#/definitions/Location"
    additionalProperties: false
  Location:
    type: "object"
    description: "A location information object."
    properties:
      latitude:
        description: "Global latitude coordinate."
        type: "number"
        format: "double"
        minimum: -90.0
        maximum: 90.0
      longitude:
        description: "Global longitude coordinate."
        type: "number"
        format: "double"
        minimum: -180.0
        maximum: 180.0
      altitudeMeters:
        description: "Altitude in meters."
        type: "number"
        format: "double"
      displayDescription:
        type: "string"
        description: "A text description of the location. Fully managed by the client."
        example:
          - "1149 Chess Dr, Foster City, CA"
          - "Zoox HQ"
          - "Work"
    required:
      - latitude
      - longitude
    additionalProperties: false
  UserList:
    description: "A list of Maestro users."
    type: "object"
    properties:
      metadata:
        $ref: "#/definitions/ListMetadata"
      items:
        type: "array"
        items:
          $ref: "#/definitions/User"
    required:
      - "metadata"
      - "items"
    additionalProperties: false
  Group:
    description: "A Maestro user group."
    type: "object"
    properties:
      id:
        type: "string"
        format: "uuid"
        readOnly: true
      name:
        type: "string"
      description:
        type: "string"
      members:
        description: "Group members. For requests, only the IDs will be honored."
        type: "array"
        items:
          $ref: "#/definitions/User"
      expiration:
        description: "Time in epoch seconds after which the resource expires."
        type: "integer"
        format: "int64"
      # required for REQUESTS ONLY: name
      # required for RESPONSES ONLY: id
    additionalProperties: false
  GroupList:
    description: "A list of Maestro user groups."
    type: "object"
    properties:
      metadata:
        $ref: "#/definitions/ListMetadata"
      items:
        type: "array"
        items:
          $ref: "#/definitions/Group"
    required:
      - "metadata"
      - "items"
    additionalProperties: false
  ListMetadata:
    type: "object"
    description: "Provides metadata for a list resource."
    properties:
      # TODO: ? Consider cursor-based pagniation?
      limit:
        type: "integer"
        description: "The maximum number of resources provided in the list."
      offset:
        type: "integer"
        description: "The offset from which the resources are fetched."
      orderBy:
        type: "string"
        description: "The property on which the resources are sorted."
      direction:
        type: "string"
        description: "The sorting direction."
        enum:
          - "ASCENDING"
          - "DESCENDING"
      totalCount:
        type: "integer"
        description: "The total number of resources available."
    required:
      - totalCount
    additionalProperties: false
  ErrorInfo:
    type: "object"
    description: "Object containing error information."
    properties:
      statusCode:
        type: "integer"
        description: "Error status code."
        # readOnly: true
      message:
        type: "string"
        description: "Error message."
        # readOnly: true
    required:
      - "statusCode"
      - "message"
    additionalProperties: false
  RideServicesResponse:
    type: object
    description: Response type for "get_ride_services"
    properties:
      items:
        type: array
        items:
          $ref: "#/definitions/RideService"
      metadata:
        $ref: "#/definitions/ListMetadata"
  RideService:
    type: "object"
    description: "An atomic operation that Zoox conducts for internal testing or external ride hailing service"
    properties:
      id:
        type: string
        format: uuid
        description: id of the ride service
      name:
        type: string
        description: name of the ride service
      description:
        type: string
        description: description of the ride service
      service_area_id:
        type: string
        description: id of the service area that's associated with the ride service
      hail_mode:
        type: string
        enum:
          - P2P
          - RP2P
          - FIXED
          - REVEAL
          - VH6_DEMO_CHESS
          - CONTINUOUS
      assign_mode:
        type: string
        enum:
          - AUTO
          - MANUAL
      robot_ids:
        type: array
        items:
          type: string
          format: uuid
          description: a list of robot ids
    required:
      - name
      - service_area_id
      - hail_mode
  AuthGroupResponse:
    type: "object"
    description: "Response type for get_auth_groups"
    properties:
      items:
        type: array
        items:
          $ref: "#/definitions/AuthGroup"
      metadata:
        $ref: "#/definitions/ListMetadata"
  AuthGroup:
    type: "object"
    description: "Authorization user group"
    properties:
      id:
        type: string
        format: uuid
        description: id of the user group on Auth0
      name:
        type: string
        description: name of the user group on Auth0
      ride_service_ids:
        type: array
        items:
          type: string
          format: uuid
          description: a list of ride service ids
  AuthGroupUpdate:
    type: "object"
    description: "Data structure that contains ride service ids to be associated with an auth group"
    properties:
      ride_service_ids:
        type: array
        items:
          type: string
          format: uuid
          description: a list of ride service ids
    required:
      - ride_service_ids

parameters:
  UserId:
    name: "userId"
    in: "path"
    description: "User ID in path."
    required: true
    type: "string"
    format: "uuid"
  GroupId:
    name: "groupId"
    in: "path"
    description: "Group ID in path."
    required: true
    type: "string"
    format: "uuid"
  UserEmailQuery:
    name: "email"
    in: "query"
    description: "User email."
    type: "string"
    format: "email"
  GroupNameQuery:
    name: "name"
    in: "query"
    description: "Group name."
    type: "string"
  UserIdsQuery:
    name: "user_ids"
    in: "query"
    description: "List of user IDs for query. For bulk queries."
    type: "array"
    items:
      type: "string"
      format: "uuid"
  GroupIdsQuery:
    name: "group_ids"
    in: "query"
    description: "List of group IDs for query. For bulk queries."
    type: "array"
    items:
      type: "string"
      format: "uuid"
  GroupDescriptionQuery:
    name: "description"
    in: "query"
    description: "Squad description in query."
    type: "string"
  Limit:
    name: "limit"
    in: "query"
    description: "The maximum number of resources provided in the page."
    type: "integer"
    minimum: 1
    maximum: 100
    default: 50
  Offset:
    name: "offset"
    in: "query"
    description: "The offset from which the resources are fetched."
    type: "integer"
    minimum: 0
    default: 0
  AuthGroupId:
    in: "path"
    name: "auth_group_id"
    description: "Id of the auth group"
    type: "string"
    format: "uuid"
    required: true
  RideServiceId:
    in: "path"
    name: "ride_service_id"
    description: "Id of the ride service"
    type: "string"
    format: "uuid"
    required: true
responses:
  NoContent:
    description: "No content (success)."
    # No schema.
  BadRequest:
    description: "Bad request."
    schema:
      $ref: "#/definitions/ErrorInfo"
  Unauthorized:
    description: "Unauthorized."
    schema:
      $ref: "#/definitions/ErrorInfo"
  Forbidden:
    description: "Forbidden."
    schema:
      $ref: "#/definitions/ErrorInfo"
  NotFound:
    description: "Resource not found or access denied."
    schema:
      $ref: "#/definitions/ErrorInfo"
  Conflict:
    description: "Resource or operation conflict."
    schema:
      $ref: "#/definitions/ErrorInfo"
  InternalServerError:
    description: "Internal server error."
    schema:
      $ref: "#/definitions/ErrorInfo"
  NotImplemented:
    description: "Not implemented."
    schema:
      $ref: "#/definitions/ErrorInfo"
