Skip to content

Commit

Permalink
Access rights fixes (#891)
Browse files Browse the repository at this point in the history
  • Loading branch information
michalrentka authored Apr 2, 2024
1 parent 4244cbb commit a27379d
Show file tree
Hide file tree
Showing 35 changed files with 576 additions and 330 deletions.
11 changes: 11 additions & 0 deletions ZShare/View Controllers/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,17 @@ final class ShareViewController: UIViewController {
return L10n.Errors.Shareext.groupQuotaReached(groupName)
}

case .forbidden(let libraryId):
switch libraryId {
case .custom:
return L10n.Errors.Shareext.forbidden(L10n.Libraries.myLibrary)

case .group(let groupId):
let group = try? self.dbStorage.perform(request: ReadGroupDbRequest(identifier: groupId), on: .main)
let groupName = group?.name ?? "\(groupId)"
return L10n.Errors.Shareext.forbidden(groupName)
}

case .downloadedFileNotPdf, .md5Missing, .mtimeMissing:
return nil
}
Expand Down
14 changes: 12 additions & 2 deletions ZShare/ViewModels/ExtensionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ final class ExtensionViewModel {
case parseError(Parsing.Error)
case schemaError(SchemaError)
case quotaLimit(LibraryIdentifier)
case forbidden(LibraryIdentifier)
case webDavNotVerified
case webDavFailure
case md5Missing
Expand Down Expand Up @@ -1054,8 +1055,17 @@ final class ExtensionViewModel {
case .responseValidationFailed(let reason):
switch reason {
case .unacceptableStatusCode(let code):
if code == 413, let libraryId = libraryId {
return .quotaLimit(libraryId)
if let libraryId {
switch code {
case 413:
return .quotaLimit(libraryId)

case 403:
return .forbidden(libraryId)

default:
break
}
}
return defaultError

Expand Down
6 changes: 0 additions & 6 deletions Zotero.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,10 @@
B30566C323FC051F003304F2 /* SyncObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305655D23FC051E003304F2 /* SyncObject.swift */; };
B30566C423FC051F003304F2 /* DeleteBatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305655E23FC051E003304F2 /* DeleteBatch.swift */; };
B30566C523FC051F003304F2 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305655F23FC051E003304F2 /* Tag.swift */; };
B30566C623FC051F003304F2 /* LibraryObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305656023FC051E003304F2 /* LibraryObject.swift */; };
B30566C723FC051F003304F2 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305656123FC051E003304F2 /* AppGroup.swift */; };
B30566C823FC051F003304F2 /* SortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305656223FC051E003304F2 /* SortType.swift */; };
B30566D923FC0769003304F2 /* tinymce in Resources */ = {isa = PBXBuildFile; fileRef = B30566D823FC0769003304F2 /* tinymce */; };
B30566DA23FC07E0003304F2 /* Library.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305653923FC051E003304F2 /* Library.swift */; };
B30566DB23FC07E7003304F2 /* LibraryObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305656023FC051E003304F2 /* LibraryObject.swift */; };
B30566DC23FC07EE003304F2 /* ItemResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305654623FC051E003304F2 /* ItemResponse.swift */; };
B30566E223FC0810003304F2 /* DeletionsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305648F23FC051E003304F2 /* DeletionsRequest.swift */; };
B30566E323FC0815003304F2 /* UpdatesRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B305649023FC051E003304F2 /* UpdatesRequest.swift */; };
Expand Down Expand Up @@ -1428,7 +1426,6 @@
B305655D23FC051E003304F2 /* SyncObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncObject.swift; sourceTree = "<group>"; };
B305655E23FC051E003304F2 /* DeleteBatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteBatch.swift; sourceTree = "<group>"; };
B305655F23FC051E003304F2 /* Tag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = "<group>"; };
B305656023FC051E003304F2 /* LibraryObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibraryObject.swift; sourceTree = "<group>"; };
B305656123FC051E003304F2 /* AppGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppGroup.swift; sourceTree = "<group>"; };
B305656223FC051E003304F2 /* SortType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortType.swift; sourceTree = "<group>"; };
B30566D823FC0769003304F2 /* tinymce */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tinymce; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2636,7 +2633,6 @@
B305653823FC051E003304F2 /* KeyedResponse.swift */,
B305653923FC051E003304F2 /* Library.swift */,
B341C8CA25CBFAD3005562E5 /* LibraryIdentifier.swift */,
B305656023FC051E003304F2 /* LibraryObject.swift */,
B361A3002511F98700271173 /* LinkMode.swift */,
B3E44641248FBE9B007FE8AB /* LinkType.swift */,
B39D336723FFD96C00EF2ACB /* Note.swift */,
Expand Down Expand Up @@ -4815,7 +4811,6 @@
B3830CF625545EE400910FE0 /* TagPickerCell.swift in Sources */,
B30565C623FC051E003304F2 /* ReadDeletedObjectsDbRequest.swift in Sources */,
B30566AF23FC051F003304F2 /* LibraryResponse.swift in Sources */,
B30566C623FC051F003304F2 /* LibraryObject.swift in Sources */,
B3868537270D90640068A022 /* RawDataEncoding.swift in Sources */,
B37C5B6D26453C58009A37E5 /* NoteEditorAction.swift in Sources */,
B30566C223FC051F003304F2 /* LibraryData.swift in Sources */,
Expand Down Expand Up @@ -5567,7 +5562,6 @@
B3501F5425139B40007961DB /* Rounding+Extensions.swift in Sources */,
B34341A1260A0A4800093E63 /* CollectionIdentifier.swift in Sources */,
B3868538270D92DA0068A022 /* RawDataEncoding.swift in Sources */,
B30566DB23FC07E7003304F2 /* LibraryObject.swift in Sources */,
B30566DC23FC07EE003304F2 /* ItemResponse.swift in Sources */,
B30566FA23FC085C003304F2 /* MarkAllLibraryObjectChangesAsSyncedDbRequest.swift in Sources */,
B305677423FC0BCD003304F2 /* ItemTitleFormatter.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions Zotero/Assets/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@
"errors.shareext.webdav_error" = "Error uploading attachment to WebDAV server";
"errors.shareext.personal_quota_reached" = "You have reached your Zotero Storage quota, and the file could not be uploaded. See your account settings for additional storage options.\n\nThe file was saved to your local library.";
"errors.shareext.group_quota_reached" = "The group \“%@\” has reached its Zotero Storage quota, and the file could not be uploaded. The group owner can view their account settings for additional storage options.\n\nThe file was saved to the local library.";
"errors.shareext.forbidden" = "You don't have necessary rights to submit this item to %@.";
"errors.shareext.webdav_not_verified" = "WebDAV verification error";
"errors.db_failure" = "Error creating database. Please try logging in again.";
"errors.logging.title" = "Debugging Error";
Expand Down Expand Up @@ -492,6 +493,7 @@
"errors.pdf.cant_add_annotations" = "Can't add annotations.";
"errors.pdf.cant_delete_annotations" = "Can't delete annotations.";
"errors.pdf.incompatible_document" = "This document is not supported.";
"errors.pdf.empty_document" = "This document is empty.";
"errors.pdf.page_index_not_int" = "Incorrect format of page stored for this document.";

"accessibility.untitled" = "Untitled";
Expand Down
12 changes: 5 additions & 7 deletions Zotero/Controllers/CustomURLController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ final class CustomURLController {
}

enum Kind {
case itemDetail(key: String, library: Library, preselectedChildKey: String?)
case pdfReader(attachment: Attachment, library: Library, page: Int?, annotation: String?, parentKey: String?, isAvailable: Bool)
case itemDetail(key: String, libraryId: LibraryIdentifier, preselectedChildKey: String?)
case pdfReader(attachment: Attachment, libraryId: LibraryIdentifier, page: Int?, annotation: String?, parentKey: String?, isAvailable: Bool)
}

private unowned let dbStorage: DbStorage
Expand Down Expand Up @@ -50,9 +50,8 @@ final class CustomURLController {

func loadSelectKind(key: String, libraryId: LibraryIdentifier) -> Kind? {
do {
let library = try dbStorage.perform(request: ReadLibraryDbRequest(libraryId: libraryId), on: .main)
let item = try dbStorage.perform(request: ReadItemDbRequest(libraryId: libraryId, key: key), on: .main)
return .itemDetail(key: (item.parent?.key ?? item.key), library: library, preselectedChildKey: item.key)
return .itemDetail(key: (item.parent?.key ?? item.key), libraryId: libraryId, preselectedChildKey: item.key)
} catch let error {
DDLogError("CustomURLConverter: library (\(libraryId)) or item (\(key)) not found - \(error)")
return nil
Expand All @@ -78,15 +77,14 @@ final class CustomURLController {
return nil
}

let library = try dbStorage.perform(request: ReadLibraryDbRequest(libraryId: libraryId), on: .main)
let parentKey = item.parent?.key

switch location {
case .local:
return .pdfReader(attachment: attachment, library: library, page: page, annotation: annotation, parentKey: parentKey, isAvailable: true)
return .pdfReader(attachment: attachment, libraryId: libraryId, page: page, annotation: annotation, parentKey: parentKey, isAvailable: true)

case .remote, .localAndChangedRemotely:
return .pdfReader(attachment: attachment, library: library, page: page, annotation: annotation, parentKey: parentKey, isAvailable: false)
return .pdfReader(attachment: attachment, libraryId: libraryId, page: page, annotation: annotation, parentKey: parentKey, isAvailable: false)

case .remoteMissing:
DDLogInfo("CustomURLConverter: attachment \(attachment.key) missing remotely")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct ReadCollectionAndLibraryDbRequest: DbResponseRequest {

switch self.collectionId {
case .collection(let key):
let rCollection = try ReadCollectionDbRequest(libraryId: self.libraryId, key: key).process(in: database)
let rCollection = try ReadRCollectionDbRequest(libraryId: self.libraryId, key: key).process(in: database)
let collection = Collection(object: rCollection, itemCount: 0)
return (collection, library)

Expand Down
27 changes: 25 additions & 2 deletions Zotero/Controllers/Database/Requests/ReadCollectionDbRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

import RealmSwift

struct ReadCollectionDbRequest: DbResponseRequest {
struct ReadRCollectionDbRequest: DbResponseRequest {
typealias Response = RCollection

let libraryId: LibraryIdentifier
Expand All @@ -19,9 +19,32 @@ struct ReadCollectionDbRequest: DbResponseRequest {
var needsWrite: Bool { return false }

func process(in database: Realm) throws -> RCollection {
guard let collection = database.objects(RCollection.self).filter(.key(self.key, in: self.libraryId)).first else {
guard let collection = database.objects(RCollection.self).filter(.key(key, in: libraryId)).first else {
throw DbError.objectNotFound
}
return collection
}
}

struct ReadCollectionDbRequest: DbResponseRequest {
typealias Response = Collection?

let collectionId: CollectionIdentifier
let libraryId: LibraryIdentifier

var needsWrite: Bool { return false }

func process(in database: Realm) throws -> Collection? {
switch collectionId {
case .collection(let key):
let rCollection = try ReadRCollectionDbRequest(libraryId: libraryId, key: key).process(in: database)
return Collection(object: rCollection, itemCount: 0)

case .custom(let type):
return Collection(custom: type)

default:
return nil
}
}
}
6 changes: 6 additions & 0 deletions Zotero/Extensions/Localizable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ internal enum L10n {
internal static let cantDeleteAnnotations = L10n.tr("Localizable", "errors.pdf.cant_delete_annotations", fallback: "Can't delete annotations.")
/// Can't update annotation.
internal static let cantUpdateAnnotation = L10n.tr("Localizable", "errors.pdf.cant_update_annotation", fallback: "Can't update annotation.")
/// This document is empty.
internal static let emptyDocument = L10n.tr("Localizable", "errors.pdf.empty_document", fallback: "This document is empty.")
/// This document is not supported.
internal static let incompatibleDocument = L10n.tr("Localizable", "errors.pdf.incompatible_document", fallback: "This document is not supported.")
/// The combined annotation would be too large.
Expand Down Expand Up @@ -588,6 +590,10 @@ internal enum L10n {
internal static let failedAdditional = L10n.tr("Localizable", "errors.shareext.failed_additional", fallback: "You can still save this page as a webpage item.")
/// Unable to save PDF
internal static let fileNotPdf = L10n.tr("Localizable", "errors.shareext.file_not_pdf", fallback: "Unable to save PDF")
/// You don't have necessary rights to submit this item to %@.
internal static func forbidden(_ p1: Any) -> String {
return L10n.tr("Localizable", "errors.shareext.forbidden", String(describing: p1), fallback: "You don't have necessary rights to submit this item to %@.")
}
/// The group “%@” has reached its Zotero Storage quota, and the file could not be uploaded. The group owner can view their account settings for additional storage options.
///
/// The file was saved to the local library.
Expand Down
2 changes: 2 additions & 0 deletions Zotero/Models/Database/RGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ enum GroupType: String, PersistableEnum {
}

final class RGroup: Object {
static let observableKeypathsForAccessRights = ["canEditMetadata", "canEditFiles"]

@Persisted(primaryKey: true) var identifier: Int
@Persisted var owner: Int
@Persisted var name: String
Expand Down
4 changes: 4 additions & 0 deletions Zotero/Models/Library.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ struct Library: Equatable, Identifiable, Hashable {
return self.identifier
}

var metadataAndFilesEditable: Bool {
return metadataEditable && filesEditable
}

init(customLibrary: RCustomLibrary) {
self.identifier = .custom(customLibrary.type)
self.name = customLibrary.type.libraryName
Expand Down
35 changes: 35 additions & 0 deletions Zotero/Models/LibraryIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Foundation

import RealmSwift
import RxSwift

enum LibraryIdentifier: Equatable, Hashable {
Expand Down Expand Up @@ -86,3 +87,37 @@ extension LibraryIdentifier {
}
}
}

extension LibraryIdentifier {
func observe(in dbStorage: DbStorage, changes changed: @escaping (Library) -> Void) throws -> (Library, NotificationToken?) {
return try observe(changes: changed) { groupId in
return try dbStorage.perform(request: ReadGroupDbRequest(identifier: groupId), on: .main)
}
}

func observe(in coordinator: DbCoordinator, changes changed: @escaping (Library) -> Void) throws -> (Library, NotificationToken?) {
return try observe(changes: changed) { groupId in
return try coordinator.perform(request: ReadGroupDbRequest(identifier: groupId))
}
}

private func observe(changes changed: @escaping (Library) -> Void, getGroup: (Int) throws -> RGroup) throws -> (Library, NotificationToken?) {
switch self {
case .custom(let type):
return (Library(identifier: self, name: type.libraryName, metadataEditable: true, filesEditable: true), nil)

case .group(let groupId):
let group = try getGroup(groupId)
let token = group.observe(keyPaths: RGroup.observableKeypathsForAccessRights, on: .main) { (change: ObjectChange<RGroup>) in
switch change {
case .change(let group, _):
changed(Library(group: group))

case .deleted, .error:
break
}
}
return (Library(group: group), token)
}
}
}
26 changes: 0 additions & 26 deletions Zotero/Models/LibraryObject.swift

This file was deleted.

Loading

0 comments on commit a27379d

Please sign in to comment.