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