1 ////////////////////////////////////////////////////////////////////////////
 
   3 // Copyright 2017 Realm Inc.
 
   5 // Licensed under the Apache License, Version 2.0 (the "License");
 
   6 // you may not use this file except in compliance with the License.
 
   7 // You may obtain a copy of the License at
 
   9 // http://www.apache.org/licenses/LICENSE-2.0
 
  11 // Unless required by applicable law or agreed to in writing, software
 
  12 // distributed under the License is distributed on an "AS IS" BASIS,
 
  13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14 // See the License for the specific language governing permissions and
 
  15 // limitations under the License.
 
  17 ////////////////////////////////////////////////////////////////////////////
 
  19 #ifndef REALM_OS_SYNC_PERMISSION_HPP
 
  20 #define REALM_OS_SYNC_PERMISSION_HPP
 
  22 #include "results.hpp"
 
  23 #include "shared_realm.hpp"
 
  35 // A permission encapsulates a single access level.
 
  36 // Each level includes all the capabilities of the level
 
  37 // above it (for example, 'write' implies 'read').
 
  38 enum class AccessLevel {
 
  45 // Permission object used to represent a user permission.
 
  46 // Permission objects can be passed into or returned by various permissions
 
  47 // APIs. They are immutable objects.
 
  49     // The path of the Realm to which this permission pertains.
 
  54     // Return the string description of an `AccessLevel`.
 
  55     static std::string description_for_access_level(AccessLevel level);
 
  57     // Return whether two paths are equivalent: either because they are exactly
 
  58     // equal, or because user ID subtitution of one tilde-delimited path results
 
  59     // in a path identical to the other path.
 
  60     // Warning: this method does NOT strip or add leading or trailing slashes or whitespace.
 
  61     // For example: "/~/foo" is equivalent to "/~/foo"; "/1/foo" is equivalent to "/1/foo".
 
  62     // "/~/foo" is equivalent to "/1/foo" for a user ID of 1.
 
  63     static bool paths_are_equivalent(std::string path_1, std::string path_2,
 
  64                                      const std::string& user_id_1, const std::string& user_id_2);
 
  66     // Condition is a userId or a KeyValue pair
 
  67     // Other conditions may be supported in the future
 
  70             // The permission is applied to a single user based on their user ID
 
  72             // The permission is based on any user that meets a criterion specified by key/value.
 
  77         // FIXME: turn this back into a union type
 
  79         std::pair<std::string, std::string> key_value;
 
  83         Condition(std::string id)
 
  85         , user_id(std::move(id))
 
  88         Condition(std::string key, std::string value)
 
  89         : type(Type::KeyValue)
 
  90         , key_value(std::make_pair(std::move(key), std::move(value)))
 
  97     /// Create a Permission value from an `Object`.
 
 100     /// Create a Permission value from raw values.
 
 101     Permission(std::string path, AccessLevel, Condition, Timestamp updated_at=Timestamp());
 
 104 struct PermissionOffer {
 
 107     Timestamp expiration;
 
 112     // Consumers of these APIs need to pass in a method which creates a Config with the proper
 
 113     // SyncConfig and associated callbacks, as well as the path and other parameters.
 
 114     using ConfigMaker = std::function<Realm::Config(std::shared_ptr<SyncUser>, std::string url)>;
 
 116     // Callback used to asynchronously vend permissions results.
 
 117     using PermissionResultsCallback = std::function<void(Results, std::exception_ptr)>;
 
 119     // Callback used to asynchronously vend permission offer or response URL.
 
 120     using PermissionOfferCallback = std::function<void(util::Optional<std::string>, std::exception_ptr)>;
 
 122     // Asynchronously retrieve a `Results` containing the permissions for the provided user.
 
 123     static void get_permissions(std::shared_ptr<SyncUser>, PermissionResultsCallback, const ConfigMaker&);
 
 125     // Callback used to monitor success or errors when changing permissions
 
 126     // or accepting a permission offer.
 
 127     // `exception_ptr` is null_ptr on success
 
 128     using PermissionChangeCallback = std::function<void(std::exception_ptr)>;
 
 130     // Set a permission as the provided user.
 
 131     static void set_permission(std::shared_ptr<SyncUser>, Permission, PermissionChangeCallback, const ConfigMaker&);
 
 133     // Delete a permission as the provided user.
 
 134     static void delete_permission(std::shared_ptr<SyncUser>, Permission, PermissionChangeCallback, const ConfigMaker&);
 
 136     // Create a permission offer. The callback will be passed the token, if successful.
 
 137     static void make_offer(std::shared_ptr<SyncUser>, PermissionOffer, PermissionOfferCallback, const ConfigMaker&);
 
 139     // Accept a permission offer based on the token value within the offer.
 
 140     static void accept_offer(std::shared_ptr<SyncUser>, const std::string&, PermissionOfferCallback, const ConfigMaker&);
 
 142     using AsyncOperationHandler = std::function<void(Object*, std::exception_ptr)>;
 
 145     static SharedRealm management_realm(std::shared_ptr<SyncUser>, const ConfigMaker&);
 
 146     static SharedRealm permission_realm(std::shared_ptr<SyncUser>, const ConfigMaker&);
 
 149      Perform an asynchronous operation that involves writing an object to the
 
 150      user's management Realm, and then waiting for the operation to succeed or
 
 153      The object in question must have at least `id`, `createdAt`, and `updatedAt`,
 
 154      properties to be set as part of the request, and it must report its success
 
 155      or failure by setting its `statusCode` and `statusMessage` properties.
 
 157      The callback is invoked upon success or failure, and will be called with
 
 158      exactly one of its two arguments not set to null. The object can be used to
 
 159      extract additional data to be returned to the caller.
 
 161     static void perform_async_operation(const std::string& object_type,
 
 162                                         std::shared_ptr<SyncUser>,
 
 163                                         AsyncOperationHandler,
 
 164                                         std::map<std::string, util::Any>,
 
 168 struct PermissionActionException : std::runtime_error {
 
 171     PermissionActionException(std::string message, long long code)
 
 172     : std::runtime_error(std::move(message))
 
 179 #endif /* REALM_OS_SYNC_PERMISSION_HPP */