Skip to content

Commit

Permalink
adapt users js code (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Mar 30, 2024
1 parent 1316384 commit 7abc0b9
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 58 deletions.
5 changes: 3 additions & 2 deletions rust/agama-server/src/users/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ pub async fn users_service(dbus: zbus::Connection) -> Result<Router, ServiceErro
let validation_router = validation_router(&dbus, DBUS_SERVICE, DBUS_PATH).await?;
let status_router = service_status_router(&dbus, DBUS_SERVICE, DBUS_PATH).await?;
let router = Router::new()
.route("/", get(get_info))
.route("/first_user", put(set_first_user).delete(remove_first_user))
// TODO: "/" route failing, so workaround it with /info, but it should be /api/users in the end
.route("/info", get(get_info))
.route("/user", put(set_first_user).delete(remove_first_user))
.route(
"/root_password",
put(set_root_password).delete(remove_root_password),
Expand Down
17 changes: 17 additions & 0 deletions web/src/client/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,23 @@ class HTTPClient {
}
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @return {Promise<object>} Server response.
*/
async delete(url) {
const response = await fetch(`${this.baseUrl}/${url}`, {
method: "DELETE",
});

try {
return await response.json();
} catch (e) {
console.warn("Expecting a JSON response", e);
return response.status === 200;
}
}

/**
* Registers a handler for a given type of events.
*
Expand Down
24 changes: 11 additions & 13 deletions web/src/client/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@

// @ts-check

const ISSUES_IFACE = "org.opensuse.Agama1.Issues";
const STATUS_IFACE = "org.opensuse.Agama1.ServiceStatus";
const PROGRESS_IFACE = "org.opensuse.Agama1.Progress";
const VALIDATION_IFACE = "org.opensuse.Agama1.Validation";

/**
* @typedef {new(...args: any[]) => T} GConstructor
* @template {object} T
Expand Down Expand Up @@ -245,11 +240,12 @@ const createError = (message) => {

/**
* Extends the given class with methods to get validation errors over D-Bus
* @param {string} object_path - object_path
* @template {!WithHTTPClient} T
* @param {T} superclass - superclass to extend
* @template {!WithDBusClient} T
* @param {string} validation_path - status resource path (e.g., "/manager/status").
* @param {string} service_name - service name (e.g., "org.opensuse.Agama.Manager1").
*/
const WithValidation = (superclass, object_path) => class extends superclass {
const WithValidation = (superclass, validation_path, service_name) => class extends superclass {
/**
* Returns the validation errors
*
Expand All @@ -259,12 +255,12 @@ const WithValidation = (superclass, object_path) => class extends superclass {
let errors;

try {
errors = await this.client.getProperty(object_path, VALIDATION_IFACE, "Errors");
errors = await this.client.get(validation_path);
} catch (error) {
console.error(`Could not get validation errors for ${object_path}`, error);
console.error(`Could not get validation errors for ${validation_path}`, error);
}

return errors.map(createError);
return errors.errors.map(createError);
}

/**
Expand All @@ -274,8 +270,10 @@ const WithValidation = (superclass, object_path) => class extends superclass {
* @return {import ("./dbus").RemoveFn} function to disable the callback
*/
onValidationChange(handler) {
return this.client.onObjectChanged(object_path, VALIDATION_IFACE, () => {
this.getValidationErrors().then(handler);
return this.client.onEvent("ValidationChange", ({ service, errors }) => {
if (service === service_name) {
handler(errors);
}
});
}
};
Expand Down
72 changes: 29 additions & 43 deletions web/src/client/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@

// @ts-check

import DBusClient from "./dbus";
import { WithValidation } from "./mixins";

const USERS_SERVICE = "org.opensuse.Agama.Manager1";
const USERS_IFACE = "org.opensuse.Agama.Users1";
const USERS_PATH = "/org/opensuse/Agama/Users1";
const USERS_PATH = "/users/info"; // TODO: it should be /users/ when routing in rs is solved

/**
* @typedef {object} UserResult
Expand Down Expand Up @@ -56,10 +53,10 @@ const USERS_PATH = "/org/opensuse/Agama/Users1";
*/
class UsersBaseClient {
/**
* @param {string|undefined} address - D-Bus address; if it is undefined, it uses the system bus.
* @param {import("./http").HTTPClient} client - HTTP client.
*/
constructor(address = undefined) {
this.client = new DBusClient(USERS_SERVICE, address);
constructor(client) {
this.client = client;
}

/**
Expand All @@ -68,8 +65,12 @@ class UsersBaseClient {
* @return {Promise<User>}
*/
async getUser() {
const proxy = await this.client.proxy(USERS_IFACE);
const [fullName, userName, password, autologin] = proxy.FirstUser;
const proxy = await this.client.get(USERS_PATH);
if (proxy.user === undefined) {
return { fullName: "", userName: "", password: "", autologin: false };
}

const [fullName, userName, password, autologin] = proxy.user;
return { fullName, userName, password, autologin };
}

Expand All @@ -79,8 +80,8 @@ class UsersBaseClient {
* @return {Promise<boolean>}
*/
async isRootPasswordSet() {
const proxy = await this.client.proxy(USERS_IFACE);
return proxy.RootPasswordSet;
const proxy = await this.client.get(USERS_PATH);
return proxy.root.password;
}

/**
Expand All @@ -90,16 +91,9 @@ class UsersBaseClient {
* @return {Promise<UserResult>} returns an object with the result and the issues found if error
*/
async setUser(user) {
const proxy = await this.client.proxy(USERS_IFACE);
const [result, issues] = await proxy.SetFirstUser(
user.fullName,
user.userName,
user.password,
user.autologin,
{}
);

return { result, issues };
const result = await this.client.put("/users/user", user);

return { result, issues: [] }; // TODO: check how to handle issues and result. Maybe separate call to validate?
}

/**
Expand All @@ -108,9 +102,7 @@ class UsersBaseClient {
* @return {Promise<boolean>} whether the operation was successful or not
*/
async removeUser() {
const proxy = await this.client.proxy(USERS_IFACE);
const result = await proxy.RemoveFirstUser();
return result === 0;
return this.client.delete("/users/user");
}

/**
Expand All @@ -120,9 +112,7 @@ class UsersBaseClient {
* @return {Promise<boolean>} whether the operation was successful or not
*/
async setRootPassword(password) {
const proxy = await this.client.proxy(USERS_IFACE);
const result = await proxy.SetRootPassword(password, false);
return result === 0;
return this.client.put("/users/root_password", { value: password, encrypted: false });
}

/**
Expand All @@ -131,9 +121,7 @@ class UsersBaseClient {
* @return {Promise<boolean>} whether the operation was successful or not
*/
async removeRootPassword() {
const proxy = await this.client.proxy(USERS_IFACE);
const result = await proxy.RemoveRootPassword();
return result === 0;
return this.client.delete("/users/root_password");
}

/**
Expand All @@ -142,8 +130,8 @@ class UsersBaseClient {
* @return {Promise<String>} SSH public key or an empty string if it is not set
*/
async getRootSSHKey() {
const proxy = await this.client.proxy(USERS_IFACE);
return proxy.RootSSHKey;
const proxy = await this.client.get(USERS_PATH);
return proxy.root.password || "";
}

/**
Expand All @@ -153,9 +141,7 @@ class UsersBaseClient {
* @return {Promise<boolean>} whether the operation was successful or not
*/
async setRootSSHKey(key) {
const proxy = await this.client.proxy(USERS_IFACE);
const result = await proxy.SetRootSSHKey(key);
return result === 0;
return this.client.put("/users/root_sshkey", key);
}

/**
Expand All @@ -165,15 +151,15 @@ class UsersBaseClient {
* @return {import ("./dbus").RemoveFn} function to disable the callback
*/
onUsersChange(handler) {
return this.client.onObjectChanged(USERS_PATH, USERS_IFACE, changes => {
if (changes.RootPasswordSet) {
return this.client.ws.onEvent((event) => {
if (event.type === "RootPasswordChanged") {
// @ts-ignore
return handler({ rootPasswordSet: changes.RootPasswordSet.v });
} else if (changes.RootSSHKey) {
return handler({ rootSSHKey: changes.RootSSHKey.v.toString() });
} else if (changes.FirstUser) {
return handler({ rootPasswordSet: event.password_is_set });
} else if (event.type === "RootSSHKeyChanged") {
return handler({ rootSSHKey: event.key.toString() });
} else if (event.type === "FirstUserChanged") {
// @ts-ignore
const [fullName, userName, password, autologin] = changes.FirstUser.v;
const { fullName, userName, password, autologin } = event;
return handler({ firstUser: { fullName, userName, password, autologin } });
}
});
Expand All @@ -183,6 +169,6 @@ class UsersBaseClient {
/**
* Client to interact with the Agama users service
*/
class UsersClient extends WithValidation(UsersBaseClient, USERS_PATH) { }
class UsersClient extends WithValidation(UsersBaseClient, "users/validation", "/org/opensuse/Agama/Users1") { }

export { UsersClient };
1 change: 1 addition & 0 deletions web/src/components/overview/OverviewPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default function OverviewPage() {
>
<ProductSection />
<L10nSection />
<UsersSection showErrors={showErrors} />
</Page>
);
}

0 comments on commit 7abc0b9

Please sign in to comment.