Skip to content

Commit

Permalink
feat: add user accounts page
Browse files Browse the repository at this point in the history
Co-authored-by: Antoine C <hi@acolombier.dev>
  • Loading branch information
mmstick and acolombier authored Dec 11, 2024
1 parent 00b8b2b commit 8e5afbf
Show file tree
Hide file tree
Showing 14 changed files with 1,179 additions and 147 deletions.
263 changes: 151 additions & 112 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion cosmic-settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"
license = "GPL-3.0-only"

[dependencies]
accounts-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
anyhow = "1.0"
as-result = "0.2.1"
ashpd = { version = "0.9", default-features = false, features = [
Expand Down Expand Up @@ -57,18 +58,20 @@ sunrise = "1.0.1"
tachyonix = "0.3.1"
timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
tokio = { workspace = true, features = ["fs", "io-util", "sync"] }
tracing = "0.1.40"
tracing = "0.1.41"
tracing-subscriber = "0.3.18"
udev = { version = "0.9.0", optional = true }
upower_dbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
bluez-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
url = "2.5.2"
xkb-data = "0.2.1"
zbus = { version = "4.4.0", features = ["tokio"], optional = true }
zbus_polkit = { version = "4.0.0" }
ustr = "1.0.0"
fontdb = "0.16.2"
fixed_decimal = "0.5.6"
mime = "0.3.17"
rustix = "0.38.41"

[dependencies.cosmic-settings-subscriptions]
git = "https://github.com/pop-os/cosmic-settings-subscriptions"
Expand Down Expand Up @@ -104,6 +107,7 @@ linux = [
"page-power",
"page-region",
"page-sound",
"page-users",
"page-window-management",
"page-workspaces",
"xdg-portal",
Expand All @@ -129,6 +133,7 @@ page-networking = [
page-power = ["dep:upower_dbus", "dep:zbus"]
page-region = ["dep:lichen-system", "dep:locale1"]
page-sound = ["dep:cosmic-settings-subscriptions"]
page-users = ["dep:accounts-zbus"]
page-window-management = ["dep:cosmic-settings-config"]
page-workspaces = ["dep:cosmic-comp-config"]

Expand Down
8 changes: 8 additions & 0 deletions cosmic-settings/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl SettingsApp {
PageCommands::Time => self.pages.page_id::<time::Page>(),
#[cfg(feature = "page-input")]
PageCommands::Touchpad => self.pages.page_id::<input::touchpad::Page>(),
#[cfg(feature = "page-users")]
PageCommands::Users => self.pages.page_id::<system::users::Page>(),
#[cfg(feature = "page-networking")]
PageCommands::Vpn => self.pages.page_id::<networking::vpn::Page>(),
Expand Down Expand Up @@ -504,6 +505,13 @@ impl cosmic::Application for SettingsApp {
}
}

#[cfg(feature = "page-users")]
crate::pages::Message::User(message) => {
if let Some(page) = self.pages.page_mut::<system::users::Page>() {
return page.update(message).map(Into::into);
}
}

#[cfg(feature = "page-input")]
crate::pages::Message::SystemShortcuts(message) => {
if let Some(page) = self
Expand Down
1 change: 1 addition & 0 deletions cosmic-settings/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub enum PageCommands {
#[cfg(feature = "page-input")]
Touchpad,
/// Users settings page
#[cfg(feature = "page-users")]
Users,
/// VPN settings page
#[cfg(feature = "page-networking")]
Expand Down
2 changes: 2 additions & 0 deletions cosmic-settings/src/pages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ pub enum Message {
Region(time::region::Message),
#[cfg(feature = "page-sound")]
Sound(sound::Message),
#[cfg(feature = "page-users")]
User(system::users::Message),
#[cfg(feature = "page-input")]
SystemShortcuts(input::keyboard::shortcuts::ShortcutMessage),
#[cfg(feature = "page-input")]
Expand Down
4 changes: 4 additions & 0 deletions cosmic-settings/src/pages/system/default_apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ impl page::Page<crate::pages::Message> for Page {
&mut self,
_sender: mpsc::Sender<crate::pages::Message>,
) -> Task<crate::pages::Message> {
if let Some(handle) = self.on_enter_handle.take() {
handle.abort();
}

let (task, on_enter_handle) = Task::future(async move {
let mut list = mime_apps::List::default();
list.load_from_paths(&mime_apps::list_paths());
Expand Down
10 changes: 9 additions & 1 deletion cosmic-settings/src/pages/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod about;
#[cfg(feature = "page-default-apps")]
pub mod default_apps;
pub mod firmware;
#[cfg(feature = "page-users")]
pub mod users;

use cosmic_settings_page as page;
Expand All @@ -29,16 +30,23 @@ impl page::AutoBind<crate::pages::Message> for Page {
fn sub_pages(
mut page: page::Insert<crate::pages::Message>,
) -> page::Insert<crate::pages::Message> {
page = page.sub_page::<users::Page>();
#[cfg(feature = "page-users")]
{
page = page.sub_page::<users::Page>();
}

#[cfg(feature = "page-about")]
{
page = page.sub_page::<about::Page>();
}

page = page.sub_page::<firmware::Page>();

#[cfg(feature = "page-default-apps")]
{
page = page.sub_page::<default_apps::Page>();
}

page
}
}
32 changes: 0 additions & 32 deletions cosmic-settings/src/pages/system/users.rs

This file was deleted.

137 changes: 137 additions & 0 deletions cosmic-settings/src/pages/system/users/getent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2024 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only

use std::io::{BufRead, BufReader};
use std::process::Stdio;
use std::str::FromStr;

pub fn passwd(range: (u64, u64)) -> Vec<PasswdUser> {
let spawn_res = std::process::Command::new("getent")
.arg("passwd")
.stdin(Stdio::null())
.stderr(Stdio::null())
.stdout(Stdio::piped())
.spawn();

let mut users = Vec::new();

if let Ok(mut child) = spawn_res {
let stdout = child.stdout.take().unwrap();
let mut reader = BufReader::new(stdout);
let mut line = String::new();

loop {
line.clear();
match reader.read_line(&mut line) {
Ok(0) | Err(_) => break,
_ => (),
}

if let Ok(user) = line.trim().parse::<PasswdUser>() {
if user.uid >= range.0 && user.uid <= range.1 {
users.push(user);
}
}
}
}

users
}

pub fn group() -> Vec<Group> {
let spawn_res = std::process::Command::new("getent")
.arg("group")
.stdin(Stdio::null())
.stderr(Stdio::null())
.stdout(Stdio::piped())
.spawn();

let mut groups = Vec::new();

if let Ok(mut child) = spawn_res {
let stdout = child.stdout.take().unwrap();
let mut reader = BufReader::new(stdout);
let mut line = String::new();

loop {
line.clear();
match reader.read_line(&mut line) {
Ok(0) | Err(_) => break,
_ => (),
}

if let Ok(group) = line.trim().parse::<Group>() {
groups.push(group);
}
}
}

groups
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Group {
pub uid: u64,
pub name: Box<str>,
pub users: Vec<Box<str>>,
}

impl FromStr for Group {
type Err = ();

fn from_str(line: &str) -> Result<Self, Self::Err> {
let mut fields = line.split(':');

Ok(Group {
name: fields.next().ok_or(())?.into(),
uid: fields.nth(1).ok_or(())?.parse().map_err(|_| ())?,
users: fields
.next()
.ok_or(())?
.split(',')
.map(Box::from)
.collect::<Vec<_>>(),
})
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PasswdUser {
pub uid: u64,
pub username: Box<str>,
pub full_name: Box<str>,
}

impl FromStr for PasswdUser {
type Err = ();

fn from_str(line: &str) -> Result<Self, Self::Err> {
let mut fields = line.split(':');

Ok(PasswdUser {
username: fields.next().ok_or(())?.into(),
uid: fields.nth(1).ok_or(())?.parse().map_err(|_| ())?,
full_name: fields.nth(1).ok_or(())?.split(',').next().ok_or(())?.into(),
})
}
}

#[cfg(test)]
mod tests {
use super::PasswdUser;

#[test]
fn passwd() {
const EXAMPLE: &str =
"speech-dispatcher:x:109:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false";

assert_eq!(
EXAMPLE.parse::<PasswdUser>(),
Ok(PasswdUser {
username: Box::from("speech-dispatcher"),
uid: 109,
full_name: Box::from("Speech Dispatcher")
})
);
}
}
Loading

0 comments on commit 8e5afbf

Please sign in to comment.