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)
 | 
			
		||||
 | 
			
		||||
### 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)
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
 | 
			
		||||
* Public sign-up page (disabled by default)
 | 
			
		||||
* Private sign-up links
 | 
			
		||||
* New CLI commands
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,6 +83,10 @@ impl GpodderRepository {
 | 
			
		|||
        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(
 | 
			
		||||
        &self,
 | 
			
		||||
        username: &str,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,9 @@ pub trait GpodderAuthStore {
 | 
			
		|||
    /// Insert a new user into the data store
 | 
			
		||||
    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
 | 
			
		||||
    ///
 | 
			
		||||
    /// The `last_seen` timestamp's precision should be at least accurate to the second
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ use diesel::prelude::*;
 | 
			
		|||
 | 
			
		||||
use crate::schema::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Queryable, Selectable)]
 | 
			
		||||
#[derive(Clone, Queryable, Selectable, AsChangeset)]
 | 
			
		||||
#[diesel(table_name = users)]
 | 
			
		||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
 | 
			
		||||
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 {
 | 
			
		||||
    fn from(value: SignupLink) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +69,18 @@ impl gpodder::GpodderAuthStore for SqliteRepository {
 | 
			
		|||
            .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> {
 | 
			
		||||
        match sessions::table
 | 
			
		||||
            .inner_join(users::table)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
use clap::{Args, Subcommand};
 | 
			
		||||
use clap::{ArgAction, Args, Subcommand};
 | 
			
		||||
 | 
			
		||||
use super::CliError;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +22,12 @@ pub enum UserCommand {
 | 
			
		|||
    Add { username: String, password: String },
 | 
			
		||||
    /// Generate a signup link ID
 | 
			
		||||
    GenerateSignupLink,
 | 
			
		||||
    /// Give or remove admin privileges to a user
 | 
			
		||||
    SetAdmin {
 | 
			
		||||
        username: String,
 | 
			
		||||
        #[clap(action=ArgAction::Set)]
 | 
			
		||||
        is_admin: bool,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Command {
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +73,11 @@ impl UserCommand {
 | 
			
		|||
 | 
			
		||||
                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(())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue