diff --git a/include/class-Log.php b/include/class-Log.php index 124b160..3701509 100644 --- a/include/class-Log.php +++ b/include/class-Log.php @@ -1,337 +1,344 @@ . // make sure that this class is loaded at startup class_exists( User::class ); class_exists( Domain::class ); class_exists( Mailbox::class ); class_exists( Mailforwardfrom::class ); trait LogTrait { /** * Get the log actor name * * @return string */ public function getLogActorFirm() { return User::firm( $this->get( 'actor_uid' ) ); } /** * Get the action family * * @return string */ public function getLogFamily() { return $this->get( 'log_family' ); } /** * Get the action */ public function getLogAction() { return $this->get( 'log_action' ); } /** * Get the action */ public function getLogDate() { return $this->get( 'log_timestamp' ); } /** * Get the log message * * @param array $args Arguments * @return self */ public function getLogMessage( $args ) { $family = $this->getLogFamily(); $action = $this->getLogAction(); // trigger the right message family switch( $family ) { case 'domain': return self::domainMessage( $action, $this, $args ); case 'mailbox': return self::mailboxMessage( $action, $this, $args ); case 'mailforward': return self::mailforwardMessage( $action, $this, $args ); case 'user': return self::userMessage( $action, $this, $args ); } return self::unknownAction( $family, $action ); } /** * Get the log message alongside the date and the actor name * * @param array $args Arguments * @return self */ public function getLogMessageWithDateAndUser( $args ) { $actor = $args['actor'] ?? $this; // create the Actor firm from the passed User object or from the Log $actor_firm = $actor instanceof User ? $actor->getUserFirm() : $actor->getLogActorFirm(); return sprintf( "%s - %s %s", $this->getLogDate()->format( __( "Y-m-d H:i" ) ), $actor_firm, $this->getLogMessage( $args ) ); } protected function normalizeLog() { $this->datetimes( 'log_timestamp' ); } } /** * A generic log of an action * * Something happened. Dunno what. */ class Log extends Queried { use LogTrait; use UserTrait; use DomainTrait; use MailboxTrait; use MailforwardfromTrait; public function __construct() { $this->normalizeLog(); } /** * Database table name */ const T = 'log'; /** * Generate a Domain-related message * * @param string $action The related action name * @param object $log * @param array $args Arguments * @return string Message */ public static function domainMessage( $action, $log, $args ) { /** * You can pass some objects to build the message: * * A complete 'actor' User object * A complete 'domain' Domain object */ $domain = $args['domain'] ?? $log; $plan = $args['plan'] ?? $log; switch( $action ) { // an administrator created the Domain case 'create': return sprintf( __( "created the domain %s" ), $domain->getDomainFirm() ); // an administrator has changed the Plan for a Domain case 'plan.change': return sprintf( __( "changed the Plan for %s to %s" ), $domain->getDomainFirm(), esc_html( $plan->getPlanName() ) ); } // default dummy message return self::unknownAction( 'domain', $action ); } /** * Generate a Mailbox-related message * * @param string $action The related action name * @param object $log * @param array $args Arguments * @return string Message */ public static function mailboxMessage( $action, $log, $args ) { /** * You can pass some objects to build the message: * * A complete 'actor' User object * A complete 'domain' Domain object * A complete 'mailbox' Mailbox object */ $actor = $args['actor'] ?? $log; $domain = $args['domain'] ?? $log; $mailbox = $args['mailbox'] ?? $log; $mailbox_firm = Mailbox::firm( $domain->getDomainName(), $mailbox->getMailboxUsername() ); // trigger the right action message switch( $action ) { // the mailbox was created case 'create': return sprintf( __( "created the mailbox %s" ), $mailbox_firm ); // the description was changed case 'description.change': return sprintf( __( "edited description of %s" ), $mailbox_firm ); case 'newpassword': return sprintf( __( "reset password of %s" ), $mailbox_firm ); } // default dummy message return self::unknownAction( 'mailbox', $action ); } /** * Generate a Mailforward-related message * * @param string $action The related action name * @param object $log * @param array $args Arguments * @return string Message */ public static function mailforwardMessage( $action, $log, $args ) { /** * You can pass some objects to build the message: * * A complete 'domain' Domain object * A complete 'mailbox' Mailbox object */ $domain = $args['domain'] ?? $log; $mailforward = $args['mailforward'] ?? $log; if( $mailforward ) { $firm = Mailforwardfrom::firm( $domain->getDomainName(), $mailforward->getMailforwardfromUsername() ); } else { $firm = $domain->getDomainFirm(); } // trigger the right action message switch( $action ) { // a Mailforward destination was added case 'add.destination': return sprintf( __( "added a destination for %s" ), $firm ); // a Mailforward destination was removed case 'remove.destination': return sprintf( __( "removed a destination for %s" ), $firm ); // a Mailforward mailbox was created case 'create': return sprintf( __( "created %s" ), $firm ); case 'delete': return sprintf( __( "deleted an %s mail forwarding" ), $firm ); } // default dummy message return self::unknownAction( 'mailforward', $action ); } /** * Generate a User-related message * * @param string $action The related action name * @param object $log * @param array $args Arguments * @return string Message */ public static function userMessage( $action, $log, $args ) { /** * You can pass some objects to build the message: * * A complete 'marionette' User object */ $marionette_uid = $log->marionette_uid ?? null; $firm = '?'; if( $marionette_uid ) { $firm = User::firm( $marionette_uid ); } // trigger the right action message switch( $action ) { + // an User creation + case 'create': + return sprintf( + __( "gave birth to %s" ), + $firm + ); + // a password reset case 'password.reset': return sprintf( __( "reset password for %s" ), $firm ); } // default dummy message return self::unknownAction( 'user', $action ); } private static function unknownAction( $family, $action ) { return esc_html( sprintf( __( "misterious action about %s (%s)" ), $family, $action ) ); } } diff --git a/www/user.php b/www/user.php index 6e333d6..2782160 100644 --- a/www/user.php +++ b/www/user.php @@ -1,235 +1,247 @@ . /* * This is the single User creation/edit page */ // load framework require '../load.php'; // this page is not public require_permission( 'backend' ); // wanted informations $user = null; // URL paramenters (user_uid) list( $user_uid ) = url_parts( 1, 0 ); // eventually retrieve mailforward from database if( $user_uid ) { $user = ( new UserAPI() ) ->whereUserUID( $user_uid ) ->whereUserIsEditable() ->queryRow(); // 404 if( !$user || !$user->isUserEditable() ) { PageNotFound::spawn(); } } else { // to create an FTP user, must edit all FTP users require_permission( 'edit-user-all' ); } // register save User action if( is_action( 'save-user' ) ) { $email = $_POST['email'] ?? null; $uid = $_POST['uid'] ?? null; $name = $_POST['name'] ?? null; $surname = $_POST['surname'] ?? null; if( $email && $uid && $name && $surname ) { $email = (string) $email; // data to be saved $data = []; $data['user_email'] = $email; $data['user_name'] = $name; $data['user_surname'] = $surname; + start_transaction(); + if( $user ) { // update existing User ( new UserAPI() ) ->whereUser( $user ) ->update( $data ); } else { - // insert new User + // insert new User (arguments) $data['user_uid'] = $uid; $data['user_active'] = 0; // disable login as default $data['user_password'] = '!'; // assign an invalid password $data['user_role'] = 'user'; // assign low privileges $data[] = new DBCol( 'user_registration_date', 'NOW()', '-' ); + // insert new User ( new UserAPI() ) ->insertRow( $data ); + + // register user creation + APILog::insert( [ + 'family' => 'user', + 'action' => 'create', + 'marionette' => last_inserted_ID(), + ] ); } + commit(); + // POST -> redirect -> GET (See Other) http_redirect( User::permalink( $uid ), 303 ); } } // end register Save user action // add a Domain to the user if( is_action( 'add-domain' ) ){ // check for permissions if( !has_permission( 'edit-user-all' ) ) { error_die( "Not authorized to add a Domain" ); } // get the Domain by name $domain_name = $_POST['domain_name'] ?? null; if( !$domain_name ) { die( "Please fill that damn Domain name" ); } // search the Domain name $domain = ( new DomainAPI() ) ->whereDomainName( $domain_name ) ->queryRow(); start_transaction(); // domain ID to be assigned to the User $domain_ID = null; // does the Domain already exist? if( $domain ) { $domain_ID = $domain->getDomainID(); } else { // can I add this Domain? if( has_permission( 'edit-domain-all' ) ) { // add this Domain ( new DomainAPI() ) ->insertRow( [ 'domain_name' => $domain_name, 'domain_active' => 1, new DBCol( 'domain_born', 'NOW()', '-' ), ] ); $domain_ID = last_inserted_ID(); } } if( $domain_ID ) { $is_domain_mine = ( new DomainUserAPI() ) ->whereUser( $user ) ->whereDomainID( $domain_ID ) ->queryRow(); // is it already mine? if( !$is_domain_mine ) { // associate this domain to myself ( new DomainUserAPI() ) ->insertRow( [ 'domain_ID' => $domain_ID, 'user_ID' => $user->getUserID(), new DBCol( 'domain_user_creation_date', 'NOW()', '-' ), ] ); } } else { die( "this Domain is not registered and can't be added" ); } commit(); } // end add Domain to User // register action to generate a new password $new_password = null; if( is_action( 'change-password' ) && $user ) { start_transaction(); // generate a new password and save $new_password = generate_password(); $encrypted = User::encryptPassword( $new_password ); ( new UserAPI() ) ->whereUser( $user ) ->update( [ User::IS_ACTIVE => 1, User::PASSWORD => $encrypted, ] ); // register password reset action in the audit log APILog::insert( [ 'family' => 'user', 'marionette' => $user, 'action' => 'password.reset', ] ); commit(); // clean the session to avoid invalid cookie logins if( $user->isUserMyself() ) { logout(); } // do not refresh the page or the new password cannot be shown } // expose the User domains $user_domains = []; if( $user ) { // get User domains $user_domains = ( new DomainUserAPI() ) ->joinDomain() ->whereUser( $user ) ->orderByDomainName() ->queryGenerator(); } // spawn header Header::spawn( [ 'uid' => false, 'title-prefix' => __( "User" ), 'title' => $user ? $user->getUserUID() : __( "create" ), ] ); // spawn the page content if( $new_password ) { template( 'password-reset-show', [ 'user' => $user, 'new_password' => $new_password, ] ); } else { template( 'user', [ 'user' => $user, 'user_domains' => $user_domains, ] ); } // spawn the footer Footer::spawn();