Skip to content

Instantly share code, notes, and snippets.

@clayellis
Created July 23, 2018 17:27
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clayellis/cee738595532114173b6268a85b3c74c to your computer and use it in GitHub Desktop.
Save clayellis/cee738595532114173b6268a85b3c74c to your computer and use it in GitHub Desktop.
Verify ownership of objects in Vapor
import Vapor
import Fluent
/// An object that can be owned.
protocol Ownable {
/// The Owner type that owns this object.
associatedtype OwnerType
/// Type of the Owner's ID
associatedtype OwnerIDType
/// Key path to the owner ID
typealias OwnerIDKey = WritableKeyPath<Self, OwnerIDType>
/// A relation to the owner that owns this object.
static var ownerIDKey: OwnerIDKey { get }
}
extension Model where Self: Ownable, Self.OwnerType: Model {
/// See `Ownable`.
typealias OwnerIDType = OwnerType.ID
}
extension Ownable where Self.OwnerType: Model, Self.OwnerIDType == Self.OwnerType.ID {
/// Whether `self` is owned by the `owner`.
/// - parameter owner: The possible owner.
/// - returns: `true` if `self` is owned by `owner`, otherwise `false`.
func isOwned(by owner: OwnerType) -> Bool {
do {
return try owner.requireID() == self[keyPath: Self.ownerIDKey]
} catch {
return false
}
}
/// Checks that `self` is owned by `owner` and throws if not.
/// - parameter owner: The possible owner.
/// - parameter error: The error to throw if `owner` is not `self`'s owner.
/// Default is `Abort(.unauthorized)`.
/// - throws: `error` if `self` is not owned by the `owner`.
func requireOwner(_ owner: OwnerType, orThrow error: Error = Abort(.unauthorized)) throws {
guard isOwned(by: owner) else {
throw error
}
}
}
extension Model {
/// Whether `self` owns the `object`.
/// - parameter object: The object that `self` might own.
/// - returns: `true` is `self` owns `object`, otherwise `false`.
func owns<T: Ownable>(_ object: T) -> Bool where T.OwnerType == Self, Self.ID == T.OwnerIDType {
return object.isOwned(by: self)
}
/// Checks that `self` owns `object` and throws if not.
/// - parameter object: The object that `self` might own.
/// - parameter error: The error to throw if `self` does not own `object`.
/// Default is `Abort(.unauthorized)`.
/// - throws: `error` if `self` does not own `object`.
func requireOwnership<T: Ownable>(of object: T, orThrow error: Error = Abort(.unauthorized)) throws where T.OwnerType == Self, Self.ID == T.OwnerIDType {
guard self.owns(object) else {
throw error
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment