Skip to content

Commit

Permalink
fix: permission checks (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
bouassaba authored Nov 28, 2024
1 parent bc91b02 commit edf6d25
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 102 deletions.
6 changes: 4 additions & 2 deletions Sources/Screens/File/FileToolbar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ struct FileToolbar: ViewModifier {
ToolbarItem(placement: .topBarTrailing) {
tasksButton
}
ToolbarItem(placement: .topBarLeading) {
uploadMenu
if let file = fileStore.file, file.permission.ge(.editor) {
ToolbarItem(placement: .topBarLeading) {
uploadMenu
}
}
ToolbarItem(placement: .topBarLeading) {
if fileStore.entitiesIsLoading {
Expand Down
12 changes: 7 additions & 5 deletions Sources/Screens/Group/GroupMemberList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ struct GroupMemberList: View, ViewDataProvider, LoadStateProvider, TimerLifecycl
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("Members")
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button {
addMemberIsPresentable = true
} label: {
Image(systemName: "plus")
if let group = groupStore.current, group.permission.ge(.owner) {
ToolbarItem(placement: .topBarLeading) {
Button {
addMemberIsPresentable = true
} label: {
Image(systemName: "plus")
}
}
}
}
Expand Down
30 changes: 14 additions & 16 deletions Sources/Screens/Group/GroupOverview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,21 @@ struct GroupOverview: View {

var body: some View {
VStack {
if let current = groupStore.current {
VStack {
VOAvatar(name: current.name, size: 100)
.padding()
Form {
NavigationLink {
GroupMemberList(groupStore: groupStore)
} label: {
Label("Members", systemImage: "person.2")
}
NavigationLink {
GroupSettings(groupStore: groupStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
VStack {
VOAvatar(name: group.name, size: 100)
.padding()
Form {
NavigationLink {
GroupMemberList(groupStore: groupStore)
} label: {
Label("Members", systemImage: "person.2")
}
NavigationLink {
GroupSettings(groupStore: groupStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
}
}
}
Expand Down
32 changes: 17 additions & 15 deletions Sources/Screens/Group/GroupSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct GroupSettings: View, ErrorPresentable {

var body: some View {
Group {
if let group = groupStore.current {
if let current = groupStore.current {
Form {
Section(header: VOSectionHeader("Basics")) {
NavigationLink {
Expand All @@ -40,27 +40,29 @@ struct GroupSettings: View, ErrorPresentable {
HStack {
Text("Name")
Spacer()
Text(group.name)
Text(current.name)
.lineLimit(1)
.truncationMode(.tail)
.foregroundStyle(.secondary)
}
}
.disabled(isDeleting)
.disabled(isDeleting || current.permission.lt(.editor))
}
Section(header: VOSectionHeader("Advanced")) {
Button(role: .destructive) {
deleteConfirmationIsPresented = true
} label: {
VOFormButtonLabel("Delete Group", isLoading: isDeleting)
}
.disabled(isDeleting)
.confirmationDialog("Delete Group", isPresented: $deleteConfirmationIsPresented) {
Button("Delete Permanently", role: .destructive) {
performDelete()
if current.permission.ge(.owner) {
Section(header: VOSectionHeader("Advanced")) {
Button(role: .destructive) {
deleteConfirmationIsPresented = true
} label: {
VOFormButtonLabel("Delete Group", isLoading: isDeleting)
}
.disabled(isDeleting)
.confirmationDialog("Delete Group", isPresented: $deleteConfirmationIsPresented) {
Button("Delete Permanently", role: .destructive) {
performDelete()
}
} message: {
Text("Are you sure you want to delete this group?")
}
} message: {
Text("Are you sure you want to delete this group?")
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions Sources/Screens/Invitation/InvitationStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ class InvitationStore: ObservableObject {

private func fetchList(page: Int = 1, size: Int = Constants.pageSize) async throws -> VOInvitation.List? {
if let organizationID {
try await invitationClient?.fetchOutgoingList(.init(organizationID: organizationID, page: page, size: size))
try await invitationClient?.fetchOutgoingList(
.init(organizationID: organizationID, page: page, size: size, sortBy: .dateCreated, sortOrder: .desc))
} else {
try await invitationClient?.fetchIncomingList(.init(page: page, size: size))
try await invitationClient?.fetchIncomingList(
.init(page: page, size: size, sortBy: .dateCreated, sortOrder: .desc))
}
}

Expand Down
32 changes: 16 additions & 16 deletions Sources/Screens/Organization/OrganizationOverview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,28 @@ struct OrganizationOverview: View {

var body: some View {
VStack {
if let current = organizationStore.current {
VStack {
VOAvatar(name: current.name, size: 100)
.padding()
Form {
NavigationLink {
OrganizationMemberList(organizationStore: organizationStore)
} label: {
Label("Members", systemImage: "person.2")
}
VStack {
VOAvatar(name: organization.name, size: 100)
.padding()
Form {
NavigationLink {
OrganizationMemberList(organizationStore: organizationStore)
} label: {
Label("Members", systemImage: "person.2")
}
if organization.permission.ge(.owner) {
NavigationLink {
InvitationOutgoingList(organization.id)
} label: {
Label("Invitations", systemImage: "paperplane")
}
NavigationLink {
OrganizationSettings(organizationStore: organizationStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
}
NavigationLink {
OrganizationSettings(organizationStore: organizationStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
}
}
}
Expand Down
68 changes: 55 additions & 13 deletions Sources/Screens/Organization/OrganizationSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ struct OrganizationSettings: View, ErrorPresentable {
@EnvironmentObject private var tokenStore: TokenStore
@ObservedObject private var organizationStore: OrganizationStore
@Environment(\.dismiss) private var dismiss
@State private var leaveConfirmationIsPresented = false
@State private var deleteConfirmationIsPresented = false
@State private var isLeaving = false
@State private var isDeleting = false
private var onCompletion: (() -> Void)?

Expand All @@ -26,7 +28,7 @@ struct OrganizationSettings: View, ErrorPresentable {

var body: some View {
Group {
if let organization = organizationStore.current {
if let current = organizationStore.current {
Form {
Section(header: VOSectionHeader("Basics")) {
NavigationLink {
Expand All @@ -42,27 +44,44 @@ struct OrganizationSettings: View, ErrorPresentable {
HStack {
Text("Name")
Spacer()
Text(organization.name)
Text(current.name)
.lineLimit(1)
.truncationMode(.tail)
.foregroundStyle(.secondary)
}
}
.disabled(isDeleting)
.disabled(isDeleting || current.permission.lt(.editor))
}
Section(header: VOSectionHeader("Advanced")) {
Section(header: VOSectionHeader("Membership")) {
Button(role: .destructive) {
deleteConfirmationIsPresented = true
leaveConfirmationIsPresented = true
} label: {
VOFormButtonLabel("Delete Organization", isLoading: isDeleting)
VOFormButtonLabel("Leave Organization", isLoading: isLeaving)
}
.disabled(isDeleting)
.confirmationDialog("Delete Organization", isPresented: $deleteConfirmationIsPresented) {
Button("Delete Permanently", role: .destructive) {
performDelete()
.disabled(isLeaving)
.confirmationDialog("Leave Organization", isPresented: $leaveConfirmationIsPresented) {
Button("Leave", role: .destructive) {
performLeave()
}
} message: {
Text("Are you sure you want to delete this organization?")
Text("Are you sure you want to leave this organization?")
}
}
if current.permission.ge(.owner) {
Section(header: VOSectionHeader("Advanced")) {
Button(role: .destructive) {
deleteConfirmationIsPresented = true
} label: {
VOFormButtonLabel("Delete Organization", isLoading: isDeleting)
}
.disabled(isDeleting)
.confirmationDialog("Delete Organization", isPresented: $deleteConfirmationIsPresented) {
Button("Delete Permanently", role: .destructive) {
performDelete()
}
} message: {
Text("Are you sure you want to delete this organization?")
}
}
}
}
Expand All @@ -73,16 +92,35 @@ struct OrganizationSettings: View, ErrorPresentable {
.voErrorSheet(isPresented: $errorIsPresented, message: errorMessage)
}

private func performLeave() {
withErrorHandling {
try await organizationStore.leave()
return true
} before: {
isLeaving = true
} success: {
dismiss()
if let current = organizationStore.current {
reflectLeaveInStore(current.id)
}
onCompletion?()
} failure: { message in
errorMessage = message
errorIsPresented = true
} anyways: {
isLeaving = false
}
}

private func performDelete() {
let current = organizationStore.current
withErrorHandling {
try await organizationStore.delete()
return true
} before: {
isDeleting = true
} success: {
dismiss()
if let current {
if let current = organizationStore.current {
reflectDeleteInStore(current.id)
}
onCompletion?()
Expand All @@ -94,6 +132,10 @@ struct OrganizationSettings: View, ErrorPresentable {
}
}

private func reflectLeaveInStore(_ id: String) {
organizationStore.entities?.removeAll(where: { $0.id == id })
}

private func reflectDeleteInStore(_ id: String) {
organizationStore.entities?.removeAll(where: { $0.id == id })
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/Screens/Organization/OrganizationStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ class OrganizationStore: ObservableObject {
try await organizationClient?.patchName(id, options: .init(name: name))
}

func leave() async throws {
guard let current else { return }
try await organizationClient?.leave(current.id)
}

func delete() async throws {
guard let current else { return }
try await organizationClient?.delete(current.id)
Expand Down
34 changes: 16 additions & 18 deletions Sources/Screens/Workspace/WorkspaceOverview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,24 @@ struct WorkspaceOverview: View, ViewDataProvider, LoadStateProvider {
} else if let error {
VOErrorMessage(error)
} else {
if let current = workspaceStore.current {
VStack {
VOAvatar(name: workspace.name, size: 100)
.padding()
Form {
NavigationLink {
if let root = workspaceStore.root {
FileOverview(root, workspaceStore: workspaceStore)
.navigationTitle(current.name)
}
} label: {
Label("Files", systemImage: "folder")
VStack {
VOAvatar(name: workspace.name, size: 100)
.padding()
Form {
NavigationLink {
if let root = workspaceStore.root {
FileOverview(root, workspaceStore: workspaceStore)
.navigationTitle(workspace.name)
}
NavigationLink {
WorkspaceSettings(workspaceStore: workspaceStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
} label: {
Label("Files", systemImage: "folder")
}
NavigationLink {
WorkspaceSettings(workspaceStore: workspaceStore) {
dismiss()
}
} label: {
Label("Settings", systemImage: "gear")
}
}
}
Expand Down
Loading

0 comments on commit edf6d25

Please sign in to comment.