feat(otter): cli command to toggle admin status
parent
ee9db5ae36
commit
b946e1ce98
|
@ -7,8 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased](https://git.rustybever.be/Chewing_Bever/otter)
|
## [Unreleased](https://git.rustybever.be/Chewing_Bever/otter)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Ability for an account to be an admin
|
||||||
|
* CLI command to toggle admin status of users
|
||||||
|
|
||||||
## [0.3.0](https://git.rustybever.be/Chewing_Bever/otter/src/tag/0.3.0)
|
## [0.3.0](https://git.rustybever.be/Chewing_Bever/otter/src/tag/0.3.0)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
* Public sign-up page (disabled by default)
|
* Public sign-up page (disabled by default)
|
||||||
* Private sign-up links
|
* Private sign-up links
|
||||||
* New CLI commands
|
* New CLI commands
|
||||||
|
|
|
@ -83,6 +83,10 @@ impl GpodderRepository {
|
||||||
self.store.insert_user(username, &password_hash)
|
self.store.insert_user(username, &password_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_user(&self, user: models::User) -> Result<models::User, AuthErr> {
|
||||||
|
self.store.update_user(user)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate_credentials(
|
pub fn validate_credentials(
|
||||||
&self,
|
&self,
|
||||||
username: &str,
|
username: &str,
|
||||||
|
|
|
@ -51,6 +51,9 @@ pub trait GpodderAuthStore {
|
||||||
/// Insert a new user into the data store
|
/// Insert a new user into the data store
|
||||||
fn insert_user(&self, username: &str, password_hash: &str) -> Result<User, AuthErr>;
|
fn insert_user(&self, username: &str, password_hash: &str) -> Result<User, AuthErr>;
|
||||||
|
|
||||||
|
/// Update the user with the included ID with the new values
|
||||||
|
fn update_user(&self, user: User) -> Result<User, AuthErr>;
|
||||||
|
|
||||||
/// Create a new session for a user with the given session ID
|
/// Create a new session for a user with the given session ID
|
||||||
///
|
///
|
||||||
/// The `last_seen` timestamp's precision should be at least accurate to the second
|
/// The `last_seen` timestamp's precision should be at least accurate to the second
|
||||||
|
|
|
@ -2,7 +2,7 @@ use diesel::prelude::*;
|
||||||
|
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Selectable)]
|
#[derive(Clone, Queryable, Selectable, AsChangeset)]
|
||||||
#[diesel(table_name = users)]
|
#[diesel(table_name = users)]
|
||||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
|
|
|
@ -24,6 +24,17 @@ impl From<User> for gpodder::User {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<gpodder::User> for User {
|
||||||
|
fn from(value: gpodder::User) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
username: value.username,
|
||||||
|
password_hash: value.password_hash,
|
||||||
|
admin: value.admin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<SignupLink> for gpodder::SignupLink {
|
impl From<SignupLink> for gpodder::SignupLink {
|
||||||
fn from(value: SignupLink) -> Self {
|
fn from(value: SignupLink) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -58,6 +69,18 @@ impl gpodder::GpodderAuthStore for SqliteRepository {
|
||||||
.map_err(DbError::from)?)
|
.map_err(DbError::from)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_user(&self, user: gpodder::User) -> Result<gpodder::User, AuthErr> {
|
||||||
|
let conn = &mut self.pool.get().map_err(DbError::from)?;
|
||||||
|
let user: User = user.into();
|
||||||
|
|
||||||
|
Ok(diesel::update(users::table.filter(users::id.eq(user.id)))
|
||||||
|
.set(&user)
|
||||||
|
.returning(User::as_returning())
|
||||||
|
.get_result(conn)
|
||||||
|
.map(gpodder::User::from)
|
||||||
|
.map_err(DbError::from)?)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_session(&self, session_id: i64) -> Result<Option<gpodder::models::Session>, AuthErr> {
|
fn get_session(&self, session_id: i64) -> Result<Option<gpodder::models::Session>, AuthErr> {
|
||||||
match sessions::table
|
match sessions::table
|
||||||
.inner_join(users::table)
|
.inner_join(users::table)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use clap::{Args, Subcommand};
|
use clap::{ArgAction, Args, Subcommand};
|
||||||
|
|
||||||
use super::CliError;
|
use super::CliError;
|
||||||
|
|
||||||
|
@ -22,6 +22,12 @@ pub enum UserCommand {
|
||||||
Add { username: String, password: String },
|
Add { username: String, password: String },
|
||||||
/// Generate a signup link ID
|
/// Generate a signup link ID
|
||||||
GenerateSignupLink,
|
GenerateSignupLink,
|
||||||
|
/// Give or remove admin privileges to a user
|
||||||
|
SetAdmin {
|
||||||
|
username: String,
|
||||||
|
#[clap(action=ArgAction::Set)]
|
||||||
|
is_admin: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
|
@ -67,6 +73,11 @@ impl UserCommand {
|
||||||
|
|
||||||
println!("/signup/{}", link.id);
|
println!("/signup/{}", link.id);
|
||||||
}
|
}
|
||||||
|
Self::SetAdmin { username, is_admin } => {
|
||||||
|
let mut user = store.get_user(username)?;
|
||||||
|
user.admin = *is_admin;
|
||||||
|
store.update_user(user)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue