# frozen_string_literal: true module PlatformSdk module PencilSpaces # OneRoster Client which wraps the swagger generated OneRoster Management APIs class Client attr_reader :access_token, :base_url, :conn # The API only supports these roles for API managed users VALID_API_USER_ROLES = %i[Teacher Student].freeze # The API only supports these roles for users in a space VALID_SPACE_ROLES = %i[host participant].freeze DEFAULT_VISIBILITY = "private" def initialize(base_url, access_token, conn: nil) @access_token = access_token @base_url = base_url @conn = conn || build_connection end # Get a list of Spaces accessible by the account associated with your API key # @param [Hash] opts the optional parameters # @option opts [Integer] :page_number **(Optional)** - The page number of the items to return. The number of items in a page is controlled by the `pageSize` parameter. # @option opts [Integer] :page_size **(Optional)** - The max number of items to return. Setting a larger `pageSize` may result in a longer querying times # @option opts [String] :filters **(Optional)** - A base64 encoded string of the filters you wish to apply to the query. See `spacesFilterSchema` for details on all the filters applicable to your query # @return [JSON] def spaces(opts = {}) # query parameters query_params = opts[:query_params] || {} query_params[:pageNumber] = opts[:page_number] unless opts[:page_number].nil? query_params[:pageSize] = opts[:page_size] unless opts[:page_size].nil? query_params[:filters] = opts[:filters] unless opts[:filters].nil? response = get("/spaces", query_params) response.body end # Get details for a particular Space # @param [String] space_id # @return [JSON] The space object for the requested space_id def space(space_id) resource_path = "/spaces/#{space_id}" response = get(resource_path) response.body end # Create a new Space # @param [String] title # @param [Array] hosts **(Optional)** Role is not required # @param [Array] participants **(Optional)** Role is not required # @param [String] visibility **(Optional)** Default is "private" # @return [JSON] The newly created space def create_space(title, hosts: [], participants: [], visibility: DEFAULT_VISIBILITY) body = { title:, visibility:, hosts: hosts.map(&:as_json), participants: participants.map(&:as_json), notifyInvitees: false } response = post("/spaces/create", body.to_json) response.body end # Get a list of Users accessible by the account associated with your API key # @param [Hash] opts the optional parameters # @option opts [Integer] :page_number **(Optional)** - The page number of the items to return. The number of items in a page is controlled by the `pageSize` parameter. # @option opts [Integer] :page_size **(Optional)** - The max number of items to return. Setting a larger `pageSize` may result in a longer querying times # @option opts [String] :filters **(Optional)** - A base64 encoded string of the filters you wish to apply to the query. See `spacesFilterSchema` for details on all the filters applicable to your query # @return [JSON] A list of Pencil Spaces users def users(opts = {}) # query parameters query_params = opts[:query_params] || {} query_params[:pageNumber] = opts[:page_number] unless opts[:page_number].nil? query_params[:pageSize] = opts[:page_size] unless opts[:page_size].nil? query_params[:filters] = opts[:filters] unless opts[:filters].nil? response = get("/users", query_params) response.body end # Get details for a particular User # @param [String] user_id # @return [JSON] The user object for the requested user_id def user(user_id) response = get("/users/#{user_id}") response.body end # Create a login link for a user # @param [String] user_id # @param [String] redirect_url **(Optional)** The URL to redirect the user to after they login # @return [JSON] JSON with a login link for the user, i.e. { "url" => "https://pencilspaces.com/login?token=123" } def authorize_user(user_id, redirect_url: nil) raise ArgumentError, "user_id must have a value" if user_id.nil? query_params = {} query_params[:redirectUrl] = redirect_url unless redirect_url.nil? response = get("/users/#{user_id}/authorize", query_params) response.body end def create_api_user(name, role) validate_api_user_role!(role) body = { name:, userRole: role } response = @conn.post("/users/createAPIUser", body.to_json) response.body end # Update users in a space # @param [String] space_id # @param [Array] users_to_add **(Optional)** Role is required # @param [Array] users_to_modify **(Optional)** Role is required # @param [Array] users_to_remove **(Optional)** # @return [JSON] The updated space def update_users_in_space(space_id, users_to_add: [], users_to_modify: [], users_to_remove: []) validate_update_users_in_space_args!(space_id, users_to_add, users_to_modify, users_to_remove) body = { notifyInvitees: false, addUsers: users_to_add.map(&:as_json), modifyUsers: users_to_modify.map(&:as_json), removeUsers: users_to_remove.map(&:as_json) } response = patch("/spaces/#{space_id}/updateUsers", body.to_json) response.body end def update_space(space_id, title: nil) validate_update_space_args(space_id, title) body = { space: { title: title } } response = patch("/spaces/#{space_id}", body.to_json) response.body end def end_ongoing_session(space_id) raise ArgumentError, "space_id must have a value" if space_id.nil? response = post("/spaces/#{space_id}/endOngoingSession", {}.to_json) response.body end def analytics_session(session_id) raise ArgumentError, "session_id must have a value" if session_id.nil? response = get("/analytics/sessions/#{session_id}") response.body end # Get a list of Session Analytics accessible by the account associated with your API key # @param [Hash] opts the optional parameters # @option opts [Integer] :page_number **(Optional)** - The page number of the items to return. The number of items in a page is controlled by the `pageSize` parameter. # @option opts [Integer] :page_size **(Optional)** - The max number of items to return. Setting a larger `pageSize` may result in a longer querying times # @option opts [String] :filters **(Optional)** - A base64 encoded string of the filters you wish to apply to the query. See `sessionsFilterSchema` for details on all the filters applicable to your query # @return [JSON] A list of Pencil Spaces users def analytics_sessions(opts = {}) # query parameters query_params = opts[:query_params] || {} query_params[:pageNumber] = opts[:page_number] unless opts[:page_number].nil? query_params[:pageSize] = opts[:page_size] unless opts[:page_size].nil? query_params[:filters] = Base64.strict_encode64(opts[:filters].to_json) unless opts[:filters].nil? response = get("/analytics/sessions", query_params) response.body end private def build_connection Faraday.new(@base_url) do |faraday| faraday.headers = default_headers faraday.adapter Faraday.default_adapter faraday.response :json, content_type: /\bjson$/, parser_options: { symbolize_names: true } faraday.response :raise_error end end def default_headers { "Content-Type" => "application/json", "Authorization" => "Bearer #{access_token}" } end def get(path, params = {}) @conn.get(path, params) end def post(path, body) @conn.post(path, body) end def patch(path, body) @conn.patch(path, body) end def validate_update_users_in_space_args!(space_id, users_to_add, users_to_modify, users_to_remove) raise ArgumentError, "space_id must have a value" if space_id.nil? if [users_to_add, users_to_modify, users_to_remove].all?(&:empty?) raise ArgumentError, "Must provide at least one of users_to_add, users_to_modify, users_to_remove" end needs_role = users_to_add + users_to_modify needs_role.each do |user| if user.class != PlatformSdk::PencilSpaces::Models::UserWithRole raise ArgumentError, "users_to_add/users_to_modify must be an array of UserWithRole objects" end raise ArgumentError, "users_to_add and users_to_modify objects must have a role" if user.role.nil? end users_to_remove.each do |user| if user.class != PlatformSdk::PencilSpaces::Models::UserWithRole raise ArgumentError, "users_to_remove must be an array of UserWithRole objects (role not required)" end end end def validate_update_space_args(space_id, title) raise ArgumentError, "space_id must have a value" if space_id.nil? raise ArgumentError, "title must have a value" if title.nil? end def validate_api_user_role!(role) return if VALID_API_USER_ROLES.include?(role) raise ArgumentError, "Invalid role: #{role}, must be one of #{VALID_API_USER_ROLES}" end end end end