Example #1
0
 /**
  * Delete this group from the database, along with any linked user and authorization rules
  *
  * @see DatabaseInterface
  */
 public function delete()
 {
     // Can only delete an object where `id` is set
     if (!$this->_id) {
         return false;
     }
     $result = parent::delete();
     // Get connection
     $db = static::connection();
     $link_table = static::getTable('group_user')->name;
     $auth_table = static::getTable('authorize_group')->name;
     $sqlVars[":id"] = $this->_id;
     $query = "\n            DELETE FROM `{$link_table}`\n            WHERE group_id = :id";
     $stmt = $db->prepare($query);
     $stmt->execute($sqlVars);
     $query = "\n            DELETE FROM `{$auth_table}`\n            WHERE group_id = :id";
     $stmt = $db->prepare($query);
     $stmt->execute($sqlVars);
     // Reassign any primary users to the current default primary group
     $default_primary_group = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, 'is_default');
     $user_table = static::getTable('user')->name;
     $query = "\n            UPDATE `{$user_table}` \n            SET primary_group_id = :primary_group_id\n            WHERE primary_group_id = :current_id;";
     $sqlVars = [":primary_group_id" => $default_primary_group->id, ":current_id" => $this->_id];
     $stmt = $db->prepare($query);
     $stmt->execute($sqlVars);
     // TODO: assign user to the default primary group as well?
     return $result;
 }
Example #2
0
 public function pageGroupTitles()
 {
     // Access-controlled resource
     if (!$this->_app->user->checkAccess('uri_group_titles')) {
         $this->_app->notFound();
     }
     // Get a list of all groups
     $groups = GroupLoader::fetchAll();
     $this->_app->render('group-titles.html', ['page' => ['author' => $this->_app->site->author, 'title' => "Update Group Titles", 'description' => "Update the title for every user in a particular group", 'alerts' => $this->_app->alerts->getAndClearMessages()], "groups" => $groups]);
 }
 /** 
  * Processes the request to create a new user (from the admin controls).
  * 
  * Processes the request from the user creation form, checking that:
  * 1. The username and email are not already in use;
  * 2. The logged-in user has the necessary permissions to update the posted field(s);
  * 3. The submitted data is valid.
  * This route requires authentication.
  * Request type: POST
  * @see formUserCreate
  */
 public function createUser()
 {
     $post = $this->_app->request->post();
     // Load the request schema
     $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/user-create.json");
     // Get the alert message stream
     $ms = $this->_app->alerts;
     // Access-controlled resource
     if (!$this->_app->user->checkAccess('create_account')) {
         $ms->addMessageTranslated("danger", "ACCESS_DENIED");
         $this->_app->halt(403);
     }
     // Set up Fortress to process the request
     $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post);
     // Sanitize data
     $rf->sanitize();
     // Validate, and halt on validation errors.
     $error = !$rf->validate(true);
     // Get the filtered data
     $data = $rf->data();
     // Remove csrf_token from object data
     $rf->removeFields(['csrf_token']);
     // Perform desired data transformations on required fields.  Is this a feature we could add to Fortress?
     $data['display_name'] = trim($data['display_name']);
     $data['email'] = strtolower(trim($data['email']));
     $data['flag_verified'] = 1;
     // Set password as empty on initial creation.  We will then send email so new user can set it themselves via secret token
     $data['password'] = "";
     // Check if username or email already exists
     if (UserLoader::exists($data['user_name'], 'user_name')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_USERNAME_IN_USE", $data);
         $error = true;
     }
     if (UserLoader::exists($data['email'], 'email')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $data);
         $error = true;
     }
     // Halt on any validation errors
     if ($error) {
         $this->_app->halt(400);
     }
     // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY)
     $primaryGroup = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, "is_default");
     // Set default values if not specified or not authorized
     if (!isset($data['locale']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "locale"])) {
         $data['locale'] = $this->_app->site->default_locale;
     }
     if (!isset($data['title']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "title"])) {
         // Set default title for new users
         $data['title'] = $primaryGroup->new_user_title;
     }
     if (!isset($data['primary_group_id']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "primary_group_id"])) {
         $data['primary_group_id'] = $primaryGroup->id;
     }
     // Set groups to default groups if not specified or not authorized to set groups
     if (!isset($data['groups']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "groups"])) {
         $default_groups = GroupLoader::fetchAll(GROUP_DEFAULT, "is_default");
         $data['groups'] = [];
         foreach ($default_groups as $group_id => $group) {
             $data['groups'][$group_id] = "1";
         }
     }
     // Create the user
     $user = new User($data);
     // Add user to groups, including selected primary group
     $user->addGroup($data['primary_group_id']);
     foreach ($data['groups'] as $group_id => $is_member) {
         if ($is_member == "1") {
             $user->addGroup($group_id);
         }
     }
     // Create events - account creation and password reset
     $user->newEventSignUp($this->_app->user);
     $user->newEventPasswordReset();
     // Save user again after creating events
     $user->save();
     // Send an email to the user's email address to set up password
     $twig = $this->_app->view()->getEnvironment();
     $template = $twig->loadTemplate("mail/password-create.twig");
     $notification = new Notification($template);
     $notification->fromWebsite();
     // Automatically sets sender and reply-to
     $notification->addEmailRecipient($user->email, $user->display_name, ['user' => $user, 'create_password_expiration' => $this->_app->site->create_password_expiration / 3600 . " hours"]);
     try {
         $notification->send();
     } catch (\Exception\phpmailerException $e) {
         $ms->addMessageTranslated("danger", "MAIL_ERROR");
         error_log('Mailer Error: ' . $e->errorMessage());
         $this->_app->halt(500);
     }
     // Success message
     $ms->addMessageTranslated("success", "ACCOUNT_CREATION_COMPLETE", $data);
 }
 public function register()
 {
     // POST: user_name, display_name, email, title, password, passwordc, captcha, spiderbro, csrf_token
     $post = $this->_app->request->post();
     // Get the alert message stream
     $ms = $this->_app->alerts;
     // Check the honeypot. 'spiderbro' is not a real field, it is hidden on the main page and must be submitted with its default value for this to be processed.
     if (!$post['spiderbro'] || $post['spiderbro'] != "http://") {
         error_log("Possible spam received:" . print_r($this->_app->request->post(), true));
         $ms->addMessage("danger", "Aww hellllls no!");
         $this->_app->halt(500);
         // Don't let on about why the request failed ;-)
     }
     // Load the request schema
     $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/register.json");
     // Set up Fortress to process the request
     $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post);
     // Security measure: do not allow registering new users until the master account has been created.
     if (!UserLoader::exists($this->_app->config('user_id_master'))) {
         $ms->addMessageTranslated("danger", "MASTER_ACCOUNT_NOT_EXISTS");
         $this->_app->halt(403);
     }
     // Check if registration is currently enabled
     if (!$this->_app->site->can_register) {
         $ms->addMessageTranslated("danger", "ACCOUNT_REGISTRATION_DISABLED");
         $this->_app->halt(403);
     }
     // Prevent the user from registering if he/she is already logged in
     if (!$this->_app->user->isGuest()) {
         $ms->addMessageTranslated("danger", "ACCOUNT_REGISTRATION_LOGOUT");
         $this->_app->halt(200);
     }
     // Sanitize data
     $rf->sanitize();
     // Validate, and halt on validation errors.
     $error = !$rf->validate(true);
     // Get the filtered data
     $data = $rf->data();
     // Check captcha, if required
     if ($this->_app->site->enable_captcha == "1") {
         if (!$data['captcha'] || md5($data['captcha']) != $_SESSION['userfrosting']['captcha']) {
             $ms->addMessageTranslated("danger", "CAPTCHA_FAIL");
             $error = true;
         }
     }
     // Remove captcha, password confirmation from object data
     $rf->removeFields(['captcha', 'passwordc']);
     // Perform desired data transformations.  Is this a feature we could add to Fortress?
     $data['user_name'] = strtolower(trim($data['user_name']));
     $data['display_name'] = trim($data['display_name']);
     $data['email'] = strtolower(trim($data['email']));
     $data['locale'] = $this->_app->site->default_locale;
     if ($this->_app->site->require_activation) {
         $data['active'] = 0;
     } else {
         $data['active'] = 1;
     }
     // Check if username or email already exists
     if (UserLoader::exists($data['user_name'], 'user_name')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_USERNAME_IN_USE", $data);
         $error = true;
     }
     if (UserLoader::exists($data['email'], 'email')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $data);
         $error = true;
     }
     // Halt on any validation errors
     if ($error) {
         $this->_app->halt(400);
     }
     // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY)
     $primaryGroup = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, "is_default");
     $data['primary_group_id'] = $primaryGroup->id;
     // Set default title for new users
     $data['title'] = $primaryGroup->new_user_title;
     // Hash password
     $data['password'] = Authentication::hashPassword($data['password']);
     // Create the user
     $user = new User($data);
     // Add user to default groups, including default primary group
     $defaultGroups = GroupLoader::fetchAll(GROUP_DEFAULT, "is_default");
     $user->addGroup($primaryGroup->id);
     foreach ($defaultGroups as $group_id => $group) {
         $user->addGroup($group_id);
     }
     // Store new user to database
     $user->store();
     if ($this->_app->site->require_activation) {
         // Create and send activation email
         $mail = new \PHPMailer();
         $mail->From = $this->_app->site->admin_email;
         $mail->FromName = $this->_app->site->site_title;
         $mail->addAddress($user->email);
         // Add a recipient
         $mail->addReplyTo($this->_app->site->admin_email, $this->_app->site->site_title);
         $mail->Subject = $this->_app->site->site_title . " - please activate your account";
         $mail->Body = $this->_app->view()->render("common/mail/activate-new.html", ["user" => $user]);
         $mail->isHTML(true);
         // Set email format to HTML
         if (!$mail->send()) {
             $ms->addMessageTranslated("danger", "MAIL_ERROR");
             error_log('Mailer Error: ' . $mail->ErrorInfo);
             $this->_app->halt(500);
         }
         // Activation required
         $ms->addMessageTranslated("success", "ACCOUNT_REGISTRATION_COMPLETE_TYPE2");
     } else {
         // No activation required
         $ms->addMessageTranslated("success", "ACCOUNT_REGISTRATION_COMPLETE_TYPE1");
     }
 }
Example #5
0
 /** 
  * Processes the request to create a new user (from the admin controls).
  * 
  * Processes the request from the user creation form, checking that:
  * 1. The username and email are not already in use;
  * 2. The logged-in user has the necessary permissions to update the posted field(s);
  * 3. The submitted data is valid.
  * This route requires authentication.
  * Request type: POST
  * @see formUserCreate
  */
 public function createUser()
 {
     $post = $this->_app->request->post();
     // Load the request schema
     $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/user-create.json");
     // Get the alert message stream
     $ms = $this->_app->alerts;
     // Access-controlled resource
     if (!$this->_app->user->checkAccess('create_account')) {
         $ms->addMessageTranslated("danger", "ACCESS_DENIED");
         $this->_app->halt(403);
     }
     // Set up Fortress to process the request
     $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post);
     // Sanitize data
     $rf->sanitize();
     // Validate, and halt on validation errors.
     $error = !$rf->validate(true);
     // Get the filtered data
     $data = $rf->data();
     // Remove csrf_token, password confirmation from object data
     $rf->removeFields(['csrf_token, passwordc']);
     // Perform desired data transformations on required fields.  Is this a feature we could add to Fortress?
     $data['user_name'] = strtolower(trim($data['user_name']));
     $data['display_name'] = trim($data['display_name']);
     $data['email'] = strtolower(trim($data['email']));
     $data['active'] = 1;
     // Check if username or email already exists
     if (UserLoader::exists($data['user_name'], 'user_name')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_USERNAME_IN_USE", $data);
         $error = true;
     }
     if (UserLoader::exists($data['email'], 'email')) {
         $ms->addMessageTranslated("danger", "ACCOUNT_EMAIL_IN_USE", $data);
         $error = true;
     }
     // Halt on any validation errors
     if ($error) {
         $this->_app->halt(400);
     }
     // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY)
     $primaryGroup = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, "is_default");
     // Set default values if not specified or not authorized
     if (!isset($data['locale']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "locale"])) {
         $data['locale'] = $this->_app->site->default_locale;
     }
     if (!isset($data['title']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "title"])) {
         // Set default title for new users
         $data['title'] = $primaryGroup->new_user_title;
     }
     if (!isset($data['primary_group_id']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "primary_group_id"])) {
         $data['primary_group_id'] = $primaryGroup->id;
     }
     // Set groups to default groups if not specified or not authorized to set groups
     if (!isset($data['groups']) || !$this->_app->user->checkAccess("update_account_setting", ["property" => "groups"])) {
         $default_groups = GroupLoader::fetchAll(GROUP_DEFAULT, "is_default");
         $data['groups'] = [];
         foreach ($default_groups as $group_id => $group) {
             $data['groups'][$group_id] = "1";
         }
     }
     // Hash password
     $data['password'] = Authentication::hashPassword($data['password']);
     // Create the user
     $user = new User($data);
     // Add user to groups, including selected primary group
     $user->addGroup($data['primary_group_id']);
     foreach ($data['groups'] as $group_id => $is_member) {
         if ($is_member == "1") {
             $user->addGroup($group_id);
         }
     }
     // Store new user to database
     $user->store();
     // Success message
     $ms->addMessageTranslated("success", "ACCOUNT_CREATION_COMPLETE", $data);
 }
Example #6
0
 public function addGroup($group_id)
 {
     // First, load current groups for user
     $this->getGroups();
     // Return if user already in group
     if (isset($this->_groups[$group_id])) {
         return $this;
     }
     // Next, check that the requested group actually exists
     if (!GroupLoader::exists($group_id)) {
         throw new \Exception("The specified group_id ({$group_id}) does not exist.");
     }
     // Ok, add to the list of groups
     $this->_groups[$group_id] = GroupLoader::fetch($group_id);
     return $this;
 }
Example #7
0
 public function setupMasterAccount()
 {
     $post = $this->_app->request->post();
     // Get the alert message stream
     $ms = $this->_app->alerts;
     // Check the honeypot. 'spiderbro' is not a real field, it is hidden on the main page and must be submitted with its default value for this to be processed.
     if (!$post['spiderbro'] || $post['spiderbro'] != "http://") {
         error_log("Possible spam received:" . print_r($this->_app->request->post(), true));
         $ms->addMessage("danger", "Aww hellllls no!");
         $this->_app->halt(500);
         // Don't let on about why the request failed ;-)
     }
     // Do not allow registering a master account if one has already been created
     if (UserLoader::exists($this->_app->config('user_id_master'))) {
         $ms->addMessageTranslated("danger", "MASTER_ACCOUNT_EXISTS");
         $this->_app->halt(403);
     }
     // Check the configuration token
     if ($post['root_account_config_token'] != $this->_app->site->root_account_config_token) {
         $ms->addMessageTranslated("danger", "CONFIG_TOKEN_MISMATCH");
         $this->_app->halt(403);
     }
     // Load the request schema
     $requestSchema = new \Fortress\RequestSchema($this->_app->config('schema.path') . "/forms/register.json");
     // Set up Fortress to process the request
     $rf = new \Fortress\HTTPRequestFortress($ms, $requestSchema, $post);
     // Sanitize data
     $rf->sanitize();
     // Validate, and halt on validation errors.
     $error = !$rf->validate(true);
     // Get the filtered data
     $data = $rf->data();
     // Remove configuration token, password confirmation from object data
     $rf->removeFields(['root_account_config_token', 'passwordc']);
     // Perform desired data transformations.  Is this a feature we could add to Fortress?
     $data['user_name'] = strtolower(trim($data['user_name']));
     $data['display_name'] = trim($data['display_name']);
     $data['email'] = strtolower(trim($data['email']));
     $data['active'] = 1;
     $data['locale'] = $this->_app->site->default_locale;
     // Halt on any validation errors
     if ($error) {
         $this->_app->halt(400);
     }
     // Get default primary group (is_default = GROUP_DEFAULT_PRIMARY)
     $primaryGroup = GroupLoader::fetch(GROUP_DEFAULT_PRIMARY, "is_default");
     $data['primary_group_id'] = $primaryGroup->id;
     // Set default title for new users
     $data['title'] = $primaryGroup->new_user_title;
     // Hash password
     $data['password'] = Authentication::hashPassword($data['password']);
     // Create the user
     $user = new User($data, $this->_app->config('user_id_master'));
     // Add user to default groups, including default primary group
     $defaultGroups = GroupLoader::fetchAll(GROUP_DEFAULT, "is_default");
     $user->addGroup($primaryGroup->id);
     foreach ($defaultGroups as $group_id => $group) {
         $user->addGroup($group_id);
     }
     // Store new user to database, forcing it to insert the new user
     $user->store(true);
     // No activation required
     $ms->addMessageTranslated("success", "ACCOUNT_REGISTRATION_COMPLETE_TYPE1");
     // Update install status
     $this->_app->site->install_status = "new";
     $this->_app->site->root_account_config_token = "";
     $this->_app->site->store();
 }
 /** 
  * Processes the request to delete an existing group.
  * 
  * Deletes the specified group, removing associations with any users and any group-specific authorization rules.
  * Before doing so, checks that:
  * 1. The group is deleteable (as specified in the `can_delete` column in the database);
  * 2. The group is not currently set as the default primary group;
  * 3. The submitted data is valid.
  * This route requires authentication (and should generally be limited to admins or the root user).
  * Request type: POST
  * @param int $group_id the id of the group to delete.     
  */
 public function deleteGroup($group_id)
 {
     $post = $this->_app->request->post();
     // Get the target group
     $group = GroupLoader::fetch($group_id);
     // Get the alert message stream
     $ms = $this->_app->alerts;
     // Check authorization
     if (!$this->_app->user->checkAccess('delete_group', ['group' => $group])) {
         $ms->addMessageTranslated("danger", "ACCESS_DENIED");
         $this->_app->halt(403);
     }
     // Check that we are allowed to delete this group
     if ($group->can_delete == "0") {
         $ms->addMessageTranslated("danger", "CANNOT_DELETE_GROUP", ["name" => $group->name]);
         $this->_app->halt(403);
     }
     // Do not allow deletion if this group is currently set as the default primary group
     if ($group->is_default == GROUP_DEFAULT_PRIMARY) {
         $ms->addMessageTranslated("danger", "GROUP_CANNOT_DELETE_DEFAULT_PRIMARY", ["name" => $group->name]);
         $this->_app->halt(403);
     }
     $ms->addMessageTranslated("success", "GROUP_DELETION_SUCCESSFUL", ["name" => $group->name]);
     $group->delete();
     // TODO: implement Group function
     unset($group);
 }