Skip to content

Commit

Permalink
📝 [System/CoreServices + mkdocs] Update documentation and manifests
Browse files Browse the repository at this point in the history
  • Loading branch information
alicerunsonfedora committed Feb 9, 2021
1 parent d84a8ab commit 57f6ae7
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 32 deletions.
12 changes: 8 additions & 4 deletions docs/03-candella-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ The manifest file contains information about your app, as well as what the app n
- `description`: A summary of what your app does.
- `license`: The license your app falls under as an SPDX expression.
- `permissions`: A list of strings containing what permissions your app requires:
- `file_system`: Requires access to the Candella "file system"
- `notifications`: Requires access to NotificationKit to send notifications
- `system_events`: Requires access to System Events
- `virtual_platform`: Requires access to the MeteorVM platform
- `file_system`: Requires access to the Candella "file system"
- `notifications`: Requires access to NotificationKit to send notifications
- `system_events`: Requires access to System Events
- `manage_users`: Requires access to the accounts service to manage users
- `virtual_platform`: Requires access to the MeteorVM platform

The following is an example manifest:

Expand Down Expand Up @@ -106,6 +107,9 @@ Returns the path for a given icon size.

Apps can also store data for the currently logged-in user on the system; this data can be used to save preferences or other data that is necessary for app functions. App storage is handled by the `AppStorage` class and can be accessed for your app via `CAApplication.data`.

!!! warning "Declare file system permissions"
Apps that utilize app storage must include the `file_system` permission in their app manifest in the `permissions` field. Apps will not be able to access app storage if this permission isn't declared or if the user has not granted the app permission to do so.

There are four methods in `AppStorage` to help read and write data accordingly:

- `AppStorage.read(field)` will fetch the value for a field or return `None` if no value for the field was found.
Expand Down
File renamed without changes.
54 changes: 54 additions & 0 deletions docs/06-accounts-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Accounts Service

The **Accounts Service** for Candella extends the functionality of the Multiuser framework and adds support for managing users in a way that lets other services handle this functionality. This service defines a single class, `CAAccountsService`, to manage users efficiently.

!!! note "Backwards Compatibility with AliceOS"
To maintain backwards compatibility with AliceOS, the username of the currently logged-in user is set in AliceOS's `persistent.playername`. This field is commonly used by services and apps for the current player, and it also defines the player's name in games like _Doki Doki Literature Club!_.

## Viewing information about the userspace

Currently, there are two static methods available to get information about the userspace:

- `CAAccountsService.get_logged_in_user()` returns a `CAUser` object that contains the information about the currently logged-in user.
- `CAAccountsService.get_all_users()` returns a list of `CAUser` objects that contain information about all users known to Candella in the userspace.

## Managing users

While accessing user information is static and does not require instancing, `CAAccountsService` should be instanced in the service or app that requests these features to manage data more efficiently. Including an instance in your service or app ensures that no other services are using that app's copy, and it helps reduce variables in Ren'Py's store.

!!! warning "Declare user permissions"
For an app or service to manage users, the `manage_users` permission must be enabled for that service or app. This can be defined in the `permissions` field in an app's manifest and the `requisites` field in a service's manifest, respectively.

To instantiate an instance of the account manager, you'll need to pass in the service or app instance with the `manage_users` permission:

```py
class SampleCoreService(CACoreService):
def __init__(self):
CACoreService.__init__(self)
self._accounts = CAAccountsService(self)
```

### `add_user(self, username, pretty_name=None)`

Creates the user file for a given user and adds it to the user list.

**Arguments**

- username (str): The username for the new user.
- pretty_name (str): The display name for the new user.

### `change_current_user(self, username)`

Change the currently logged-in user.

**Arguments**

- username (str): The username of the user to switch to.

### `remove_user(self, username)`

Removes the specified user.

**Arguments**

- username (str): The username of the user to remove.
49 changes: 30 additions & 19 deletions game/System/CoreServices/Accounts.aoscservice/AccountsService.rpy
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ init offset = -10

init python:
import os

class CAAccountsUserNotFoundError(Exception):
"""The specified user was not found."""


class CAAccountsPermissionError(Exception):
"""The core service or app does not have permission to use CAAccountsService."""

class CAAccountsService(ASCoreServiceRepresentative):
bundleName = "Accounts Service"
bundleId = "dev.unscriptedvn.candella.accounts-service"
Expand All @@ -22,70 +25,78 @@ init python:
bundleDescription = """\
Manage multiple user accounts via the Multiuser framework.
"""

_accounts_dir = config.savedir + "/.causerland"
_users_list = []
def __init__(self):

def __init__(self, appobj):
ASCoreServiceRepresentative.__init__(self, AS_CORESERVICES_DIR + "Accounts.aoscservice/")
self._users_list = CAAccountsService.get_all_users()


# Disable access to this service on Candella apps and services that don't request this behavior.
if isinstance(appobj, CAApplication):
if "manage_users" not in appobj.permissions:
raise CAAccountsPermissionError(appobj.__class__.__name__)
elif isinstance(appobj, CACoreService):
if "manage_users" not in appobj.requisites:
raise CAAccountsPermissionError(appobj.__class__.__name__)

@staticmethod
def get_logged_in_user():
"""Returns the user information for the currently logged in user."""
_user = CAUserData(persistent.playername)
return CAUser(_user._data["name"], _user._data["prettyName"])

@staticmethod
def get_all_users():
"""Returns a list of user objects."""
users = []

if not os.path.isdir(config.savedir + "/.causerland"):
return []

for name in os.listdir(config.savedir + "/.causerland/"):
if name.startswith("."):
continue
users += [CAAccountsService._get_user(name)]
return users

@staticmethod
def _get_user(username):
"""Returns the user information for a specified user.
Arguments:
username (str): The username of the user to get.
Returns:
user (CAUser): The user information.
Raises:
If the user doesn't exist in the userland folder, a CAAccountsUserNotFoundError is raised.
"""
if username not in os.listdir(config.savedir + "/.causerland"):
raise CAAccountsUserNotFoundError(username)
_data = CAUserData(username)
return CAUser(_data._data["name"], _data._data["prettyName"])

def add_user(self, username, pretty_name=None):
"""Creates the user file for a given user and adds it to the user list.
Arguments:
username (str): The username for the new user.
pretty_name (str): The display name for the new user.
"""
CAUserData._create_user_file(username, pretty_name=pretty_name)
_users_list = CAUser(username, pretty_name)

def change_current_user(self, username):
"""Change the currently logged-in user."""
persistent.playername = username
# renpy.reload()

def remove_user(self, username):
"""Removes the specified user.
Arguments:
username (str): The username of the user to remove.
"""
Expand All @@ -96,4 +107,4 @@ init python:
continue
self._users_list.remove(user)
except:
pass
pass
3 changes: 2 additions & 1 deletion game/System/CoreServices/Caberto.aoscservice/CabertoDE.rpy
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ init python:
from time import gmtime, strftime

class CabertoShell(CACoreService):
_acct_mgr = CAAccountsService()
_wallpaper = AS_LIBRARY_DIR + "Desktop Pictures/Candella.png"
_dock = []
_drawer_open = False
Expand All @@ -23,6 +22,8 @@ init python:

def __init__(self):
CACoreService.__init__(self, AS_CORESERVICES_DIR + "Caberto.aoscservice/")
self._acct_mgr = CAAccountsService(self)

self.settings = ServiceStorage(self)

if not self.settings.read("apps_list"):
Expand Down
2 changes: 1 addition & 1 deletion game/System/CoreServices/Caberto.aoscservice/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"version": "1.0.0",
"description": "A desktop shell for Candella, inspired by Lomiri.",
"license": "Proprietary",
"requisites": ["file_system"]
"requisites": ["file_system", "manage_users"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ init python:
name = "Default Permission"
description = "A default permission."
default_state = False

def __init__(self, key, name, description, default=False):
self.key = key
self.name = name
self.description = description
self.default = default

def __eq__(self, other):
return isistance(other, CAPermission) and self.key == other.key

def __ne__(self, other):
return not self.__eq__(other)

# This dictionary contains the current system permissions, including the default AliceOS permissions. Apps that
# use CAApplication instead of ASAppRepresentative can leverage these permission objects by specifying the
# permissions needed for the app in the 'permissions' field of the app manifest.

CA_PERMISSIONS = {
"notifications": CAPermission(
"REQ_NOTIFICATIONKIT",
Expand All @@ -49,10 +49,15 @@ init python:
"Control System Events",
"System events include login, shutdown, or user switching. This can be configured in App Manager."
),
"manage_users": CAPermission(
"REQ_USERS_MANAGEMENT",
"Manage Users",
"User management includes adding, modifying, and removing users. This can be configured in App Manager."
),
"virtual_platform": CAPermission(
"REQ_METEORVM",
"Run Apps in a Virtual Environment",
"This app runs additional code in the Meteor VM platform. This can be configured in App Manager."
),
}

}

0 comments on commit 57f6ae7

Please sign in to comment.