Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions frontend/appflowy_flutter/lib/core/config/kv_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,9 @@ class KVKeys {
///
/// The value is a json list of id
static const String compactModeIds = 'compactModeIds';

/// v0.9.4: has the user clicked the upgrade to pro button
/// The value is a boolean string
static const String hasClickedUpgradeToProButton =
'hasClickedUpgradeToProButton';
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:appflowy/features/share_tab/data/models/models.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';

/// Abstract repository for managing view lock status.
Expand All @@ -26,4 +27,7 @@ abstract class PageAccessLevelRepository {
Future<FlowyResult<SharedSectionType, FlowyError>> getSectionType(
String pageId,
);

/// Get current workspace
Future<FlowyResult<UserWorkspacePB, FlowyError>> getCurrentWorkspace();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/workspace.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'
hide AFRolePB;
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:collection/collection.dart';

Expand All @@ -18,7 +19,7 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
final result = await ViewBackendService.getView(pageId);
return result.fold(
(view) {
Log.info('get view success: ${view.id}');
Log.debug('get view(${view.id}) success');
return FlowyResult.success(view);
},
(error) {
Expand All @@ -33,7 +34,7 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
final result = await ViewBackendService.lockView(pageId);
return result.fold(
(_) {
Log.info('lock view success: $pageId');
Log.debug('lock view($pageId) success');
return FlowyResult.success(null);
},
(error) {
Expand All @@ -48,7 +49,7 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
final result = await ViewBackendService.unlockView(pageId);
return result.fold(
(_) {
Log.info('unlock view success: $pageId');
Log.debug('unlock view($pageId) success');
return FlowyResult.success(null);
},
(error) {
Expand All @@ -58,6 +59,11 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
);
}

/// 1. local users have full access
/// 2. local workspace users have full access
/// 3. page creator has full access
/// 4. owner and members in public page have full access
/// 5. check the shared users list
@override
Future<FlowyResult<ShareAccessLevel, FlowyError>> getAccessLevel(
String pageId,
Expand All @@ -67,6 +73,7 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
(s) => s,
(_) => null,
);

if (user == null) {
return FlowyResult.failure(
FlowyError(
Expand All @@ -86,6 +93,41 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
return FlowyResult.success(ShareAccessLevel.fullAccess);
}

// If the user is the creator of the page, they can always have full access.
final viewResult = await getView(pageId);
final view = viewResult.fold(
(s) => s,
(_) => null,
);
if (view?.createdBy == user.id) {
return FlowyResult.success(ShareAccessLevel.fullAccess);
}

// If the page is public, the user can always have full access.
final workspaceResult = await getCurrentWorkspace();
final workspace = workspaceResult.fold(
(s) => s,
(_) => null,
);
if (workspace == null) {
return FlowyResult.failure(
FlowyError(
code: ErrorCode.Internal,
msg: 'Current workspace not found',
),
);
}

final sectionTypeResult = await getSectionType(pageId);
final sectionType = sectionTypeResult.fold(
(s) => s,
(_) => null,
);
if (sectionType == SharedSectionType.public &&
workspace.role != AFRolePB.Guest) {
return FlowyResult.success(ShareAccessLevel.fullAccess);
}

final email = user.email;

final request = GetSharedUsersPayloadPB(
Expand All @@ -100,7 +142,7 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
)
?.accessLevel
.shareAccessLevel ??
ShareAccessLevel.readAndWrite;
ShareAccessLevel.readOnly;

Log.debug('current user access level: $accessLevel, in page: $pageId');

Expand All @@ -111,8 +153,8 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
'failed to get user access level: $failure, in page: $pageId',
);

// return the read and write access level if the user is not found
return FlowyResult.success(ShareAccessLevel.readAndWrite);
// return the read access level if the user is not found
return FlowyResult.success(ShareAccessLevel.readOnly);
},
);
}
Expand All @@ -138,4 +180,27 @@ class RustPageAccessLevelRepositoryImpl implements PageAccessLevelRepository {
},
);
}

@override
Future<FlowyResult<UserWorkspacePB, FlowyError>> getCurrentWorkspace() async {
final result = await UserBackendService.getCurrentWorkspace();
final currentWorkspaceId = result.fold(
(s) => s.id,
(_) => null,
);

if (currentWorkspaceId == null) {
return FlowyResult.failure(
FlowyError(
code: ErrorCode.Internal,
msg: 'Current workspace not found',
),
);
}

final workspaceResult = await UserBackendService.getWorkspaceById(
currentWorkspaceId,
);
return workspaceResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class PageAccessLevelState {
isLocked: false,
lockCounter: 0,
sectionType: SharedSectionType.public,
accessLevel: ShareAccessLevel
.readAndWrite, // replace it with readOnly if we support offline.
accessLevel: ShareAccessLevel.readOnly,
);

const PageAccessLevelState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,18 @@ class LocalShareWithUserRepositoryImpl extends ShareWithUserRepository {
}) async {
return FlowySuccess(SharedSectionType.private);
}

@override
Future<bool> getUpgradeToProButtonClicked({
required String workspaceId,
}) async {
return false;
}

@override
Future<void> setUpgradeToProButtonClicked({
required String workspaceId,
}) async {
return;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/features/share_tab/data/models/models.dart';
import 'package:appflowy/features/util/extensions.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
Expand Down Expand Up @@ -52,12 +55,12 @@ class RustShareWithUserRepositoryImpl extends ShareWithUserRepository {

return result.fold(
(success) {
Log.info('remove users($emails) from shared page($pageId)');
Log.debug('remove users($emails) from shared page($pageId)');

return FlowySuccess(success);
},
(failure) {
Log.error('removeUserFromPage: $failure');
Log.error('remove users($emails) from shared page($pageId): $failure');

return FlowyFailure(failure);
},
Expand All @@ -74,13 +77,13 @@ class RustShareWithUserRepositoryImpl extends ShareWithUserRepository {
viewId: pageId,
emails: emails,
accessLevel: accessLevel.accessLevel,
autoConfirm: true, // TODO: remove this after the backend is ready
autoConfirm: true,
);
final result = await FolderEventSharePageWithUser(request).send();

return result.fold(
(success) {
Log.info(
Log.debug(
'share page($pageId) with users($emails) with access level($accessLevel)',
);

Expand Down Expand Up @@ -117,7 +120,7 @@ class RustShareWithUserRepositoryImpl extends ShareWithUserRepository {
final result = await UserEventUpdateWorkspaceMember(request).send();
return result.fold(
(success) {
Log.info(
Log.debug(
'change role($role) for user($email) in workspaceId($workspaceId)',
);
return FlowySuccess(success);
Expand Down Expand Up @@ -161,4 +164,28 @@ class RustShareWithUserRepositoryImpl extends ShareWithUserRepository {

return FlowySuccess(sectionType);
}

@override
Future<bool> getUpgradeToProButtonClicked({
required String workspaceId,
}) async {
final result = await getIt<KeyValueStorage>().getWithFormat(
'${KVKeys.hasClickedUpgradeToProButton}_$workspaceId',
(value) => bool.parse(value),
);
if (result == null) {
return false;
}
return result;
}

@override
Future<void> setUpgradeToProButtonClicked({
required String workspaceId,
}) async {
await getIt<KeyValueStorage>().set(
'${KVKeys.hasClickedUpgradeToProButton}_$workspaceId',
'true',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@ abstract class ShareWithUserRepository {
Future<FlowyResult<SharedSectionType, FlowyError>> getCurrentPageSectionType({
required String pageId,
});

/// Get the upgrade to pro button has been clicked.
Future<bool> getUpgradeToProButtonClicked({
required String workspaceId,
});

/// Set the upgrade to pro button has been clicked.
Future<void> setUpgradeToProButtonClicked({
required String workspaceId,
});
}
Loading
Loading