diff options
author | marvin-borner@live.com | 2018-04-16 21:09:05 +0200 |
---|---|---|
committer | marvin-borner@live.com | 2018-04-16 21:09:05 +0200 |
commit | cf14306c2b3f82a81f8d56669a71633b4d4b5fce (patch) | |
tree | 86700651aa180026e89a66064b0364b1e4346f3f /main/app/sprinkles/account/src/Database | |
parent | 619b01b3615458c4ed78bfaeabb6b1a47cc8ad8b (diff) |
Main merge to user management system - files are now at /main/public/
Diffstat (limited to 'main/app/sprinkles/account/src/Database')
17 files changed, 1846 insertions, 0 deletions
diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/ActivitiesTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/ActivitiesTable.php new file mode 100755 index 0000000..4e55c7c --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/ActivitiesTable.php @@ -0,0 +1,54 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use UserFrosting\System\Bakery\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; + +/** + * Sessions table migration + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class ActivitiesTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('activities')) { + $this->schema->create('activities', function (Blueprint $table) { + $table->increments('id'); + $table->string('ip_address', 45)->nullable(); + $table->integer('user_id')->unsigned(); + $table->string('type', 255)->comment('An identifier used to track the type of activity.'); + $table->timestamp('occurred_at')->nullable(); + $table->text('description')->nullable(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + //$table->foreign('user_id')->references('id')->on('users'); + $table->index('user_id'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('activities'); + } +}
\ No newline at end of file diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/GroupsTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/GroupsTable.php new file mode 100755 index 0000000..c74615f --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/GroupsTable.php @@ -0,0 +1,82 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\Sprinkle\Account\Database\Models\Group; +use UserFrosting\System\Bakery\Migration; + +/** + * Groups table migration + * "Group" now replaces the notion of "primary group" in earlier versions of UF. A user can belong to exactly one group. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class GroupsTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('groups')) { + $this->schema->create('groups', function(Blueprint $table) { + $table->increments('id'); + $table->string('slug'); + $table->string('name'); + $table->text('description')->nullable(); + $table->string('icon', 100)->nullable(false)->default('fa fa-user')->comment('The icon representing users in this group.'); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + $table->unique('slug'); + $table->index('slug'); + }); + + // Add default groups + $groups = [ + 'terran' => new Group([ + 'slug' => 'terran', + 'name' => 'Terran', + 'description' => 'The terrans are a young species with psionic potential. The terrans of the Koprulu sector descend from the survivors of a disastrous 23rd century colonization mission from Earth.', + 'icon' => 'sc sc-terran' + ]), + 'zerg' => new Group([ + 'slug' => 'zerg', + 'name' => 'Zerg', + 'description' => 'Dedicated to the pursuit of genetic perfection, the zerg relentlessly hunt down and assimilate advanced species across the galaxy, incorporating useful genetic code into their own.', + 'icon' => 'sc sc-zerg' + ]), + 'protoss' => new Group([ + 'slug' => 'protoss', + 'name' => 'Protoss', + 'description' => 'The protoss, a.k.a. the Firstborn, are a sapient humanoid race native to Aiur. Their advanced technology complements and enhances their psionic mastery.', + 'icon' => 'sc sc-protoss' + ]) + ]; + + foreach ($groups as $slug => $group) { + $group->save(); + } + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('groups'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/PasswordResetsTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/PasswordResetsTable.php new file mode 100755 index 0000000..e785ccc --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/PasswordResetsTable.php @@ -0,0 +1,57 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * password_resets table migration + * Manages requests for password resets. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class passwordResetsTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('password_resets')) { + $this->schema->create('password_resets', function (Blueprint $table) { + $table->increments('id'); + $table->integer('user_id')->unsigned(); + $table->string('hash'); + $table->boolean('completed')->default(0); + $table->timestamp('expires_at')->nullable(); + $table->timestamp('completed_at')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + //$table->foreign('user_id')->references('id')->on('users'); + $table->index('user_id'); + $table->index('hash'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('password_resets'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionRolesTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionRolesTable.php new file mode 100755 index 0000000..2c2990c --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionRolesTable.php @@ -0,0 +1,55 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * Permission_roles table migration + * Many-to-many mapping between permissions and roles. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class PermissionRolesTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('permission_roles')) { + $this->schema->create('permission_roles', function (Blueprint $table) { + $table->integer('permission_id')->unsigned(); + $table->integer('role_id')->unsigned(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + $table->primary(['permission_id', 'role_id']); + //$table->foreign('permission_id')->references('id')->on('permissions'); + //$table->foreign('role_id')->references('id')->on('roles'); + $table->index('permission_id'); + $table->index('role_id'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('permission_roles'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionsTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionsTable.php new file mode 100755 index 0000000..684b01a --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/PermissionsTable.php @@ -0,0 +1,262 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\Sprinkle\Account\Database\Models\Permission; +use UserFrosting\Sprinkle\Account\Database\Models\Role; +use UserFrosting\System\Bakery\Migration; + +/** + * Permissions table migration + * Permissions now replace the 'authorize_group' and 'authorize_user' tables. + * Also, they now map many-to-many to roles. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class PermissionsTable extends Migration +{ + /** + * {@inheritDoc} + */ + public $dependencies = [ + '\UserFrosting\Sprinkle\Account\Database\Migrations\v400\RolesTable', + '\UserFrosting\Sprinkle\Account\Database\Migrations\v400\PermissionRolesTable' + ]; + + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('permissions')) { + $this->schema->create('permissions', function(Blueprint $table) { + $table->increments('id'); + $table->string('slug')->comment('A code that references a specific action or URI that an assignee of this permission has access to.'); + $table->string('name'); + $table->text('conditions')->comment('The conditions under which members of this group have access to this hook.'); + $table->text('description')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('permissions'); + } + + /** + * {@inheritDoc} + */ + public function seed() + { + // Skip this if table is not empty + if (Permission::count() == 0) { + + $defaultRoleIds = [ + 'user' => Role::where('slug', 'user')->first()->id, + 'group-admin' => Role::where('slug', 'group-admin')->first()->id, + 'site-admin' => Role::where('slug', 'site-admin')->first()->id + ]; + + // Add default permissions + $permissions = [ + 'create_group' => new Permission([ + 'slug' => 'create_group', + 'name' => 'Create group', + 'conditions' => 'always()', + 'description' => 'Create a new group.' + ]), + 'create_user' => new Permission([ + 'slug' => 'create_user', + 'name' => 'Create user', + 'conditions' => 'always()', + 'description' => 'Create a new user in your own group and assign default roles.' + ]), + 'create_user_field' => new Permission([ + 'slug' => 'create_user_field', + 'name' => 'Set new user group', + 'conditions' => "subset(fields,['group'])", + 'description' => 'Set the group when creating a new user.' + ]), + 'delete_group' => new Permission([ + 'slug' => 'delete_group', + 'name' => 'Delete group', + 'conditions' => "always()", + 'description' => 'Delete a group.' + ]), + 'delete_user' => new Permission([ + 'slug' => 'delete_user', + 'name' => 'Delete user', + 'conditions' => "!has_role(user.id,{$defaultRoleIds['site-admin']}) && !is_master(user.id)", + 'description' => 'Delete users who are not Site Administrators.' + ]), + 'update_account_settings' => new Permission([ + 'slug' => 'update_account_settings', + 'name' => 'Edit user', + 'conditions' => 'always()', + 'description' => 'Edit your own account settings.' + ]), + 'update_group_field' => new Permission([ + 'slug' => 'update_group_field', + 'name' => 'Edit group', + 'conditions' => 'always()', + 'description' => 'Edit basic properties of any group.' + ]), + 'update_user_field' => new Permission([ + 'slug' => 'update_user_field', + 'name' => 'Edit user', + 'conditions' => "!has_role(user.id,{$defaultRoleIds['site-admin']}) && subset(fields,['name','email','locale','group','flag_enabled','flag_verified','password'])", + 'description' => 'Edit users who are not Site Administrators.' + ]), + 'update_user_field_group' => new Permission([ + 'slug' => 'update_user_field', + 'name' => 'Edit group user', + 'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$defaultRoleIds['site-admin']}) && (!has_role(user.id,{$defaultRoleIds['group-admin']}) || equals_num(self.id,user.id)) && subset(fields,['name','email','locale','flag_enabled','flag_verified','password'])", + 'description' => 'Edit users in your own group who are not Site or Group Administrators, except yourself.' + ]), + 'uri_account_settings' => new Permission([ + 'slug' => 'uri_account_settings', + 'name' => 'Account settings page', + 'conditions' => 'always()', + 'description' => 'View the account settings page.' + ]), + 'uri_activities' => new Permission([ + 'slug' => 'uri_activities', + 'name' => 'Activity monitor', + 'conditions' => 'always()', + 'description' => 'View a list of all activities for all users.' + ]), + 'uri_dashboard' => new Permission([ + 'slug' => 'uri_dashboard', + 'name' => 'Admin dashboard', + 'conditions' => 'always()', + 'description' => 'View the administrative dashboard.' + ]), + 'uri_group' => new Permission([ + 'slug' => 'uri_group', + 'name' => 'View group', + 'conditions' => 'always()', + 'description' => 'View the group page of any group.' + ]), + 'uri_group_own' => new Permission([ + 'slug' => 'uri_group', + 'name' => 'View own group', + 'conditions' => 'equals_num(self.group_id,group.id)', + 'description' => 'View the group page of your own group.' + ]), + 'uri_groups' => new Permission([ + 'slug' => 'uri_groups', + 'name' => 'Group management page', + 'conditions' => 'always()', + 'description' => 'View a page containing a list of groups.' + ]), + 'uri_user' => new Permission([ + 'slug' => 'uri_user', + 'name' => 'View user', + 'conditions' => 'always()', + 'description' => 'View the user page of any user.' + ]), + 'uri_user_in_group' => new Permission([ + 'slug' => 'uri_user', + 'name' => 'View user', + 'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$defaultRoleIds['site-admin']}) && (!has_role(user.id,{$defaultRoleIds['group-admin']}) || equals_num(self.id,user.id))", + 'description' => 'View the user page of any user in your group, except the master user and Site and Group Administrators (except yourself).' + ]), + 'uri_users' => new Permission([ + 'slug' => 'uri_users', + 'name' => 'User management page', + 'conditions' => 'always()', + 'description' => 'View a page containing a table of users.' + ]), + 'view_group_field' => new Permission([ + 'slug' => 'view_group_field', + 'name' => 'View group', + 'conditions' => "in(property,['name','icon','slug','description','users'])", + 'description' => 'View certain properties of any group.' + ]), + 'view_group_field_own' => new Permission([ + 'slug' => 'view_group_field', + 'name' => 'View group', + 'conditions' => "equals_num(self.group_id,group.id) && in(property,['name','icon','slug','description','users'])", + 'description' => 'View certain properties of your own group.' + ]), + 'view_user_field' => new Permission([ + 'slug' => 'view_user_field', + 'name' => 'View user', + 'conditions' => "in(property,['user_name','name','email','locale','theme','roles','group','activities'])", + 'description' => 'View certain properties of any user.' + ]), + 'view_user_field_group' => new Permission([ + 'slug' => 'view_user_field', + 'name' => 'View user', + 'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$defaultRoleIds['site-admin']}) && (!has_role(user.id,{$defaultRoleIds['group-admin']}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group','activities'])", + 'description' => 'View certain properties of any user in your own group, except the master user and Site and Group Administrators (except yourself).' + ]) + ]; + + foreach ($permissions as $slug => $permission) { + $permission->save(); + } + + // Add default mappings to permissions + $roleUser = Role::where('slug', 'user')->first(); + if ($roleUser) { + $roleUser->permissions()->sync([ + $permissions['update_account_settings']->id, + $permissions['uri_account_settings']->id, + $permissions['uri_dashboard']->id + ]); + } + + $roleSiteAdmin = Role::where('slug', 'site-admin')->first(); + if ($roleSiteAdmin) { + $roleSiteAdmin->permissions()->sync([ + $permissions['create_group']->id, + $permissions['create_user']->id, + $permissions['create_user_field']->id, + $permissions['delete_group']->id, + $permissions['delete_user']->id, + $permissions['update_user_field']->id, + $permissions['update_group_field']->id, + $permissions['uri_activities']->id, + $permissions['uri_group']->id, + $permissions['uri_groups']->id, + $permissions['uri_user']->id, + $permissions['uri_users']->id, + $permissions['view_group_field']->id, + $permissions['view_user_field']->id + ]); + } + + $roleGroupAdmin = Role::where('slug', 'group-admin')->first(); + if ($roleGroupAdmin) { + $roleGroupAdmin->permissions()->sync([ + $permissions['create_user']->id, + $permissions['update_user_field_group']->id, + $permissions['uri_group_own']->id, + $permissions['uri_user_in_group']->id, + $permissions['view_group_field_own']->id, + $permissions['view_user_field_group']->id + ]); + } + } + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/PersistencesTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/PersistencesTable.php new file mode 100755 index 0000000..b96e327 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/PersistencesTable.php @@ -0,0 +1,57 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * Persistences table migration + * Many-to-many mapping between roles and users. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class PersistencesTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('persistences')) { + $this->schema->create('persistences', function (Blueprint $table) { + $table->increments('id'); + $table->integer('user_id')->unsigned(); + $table->string('token', 40); + $table->string('persistent_token', 40); + $table->timestamp('expires_at')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + //$table->foreign('user_id')->references('id')->on('users'); + $table->index('user_id'); + $table->index('token'); + $table->index('persistent_token'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('persistences'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/RoleUsersTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/RoleUsersTable.php new file mode 100755 index 0000000..7f3648b --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/RoleUsersTable.php @@ -0,0 +1,55 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * Role_users table migration + * Many-to-many mapping between roles and users. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class RoleUsersTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('role_users')) { + $this->schema->create('role_users', function (Blueprint $table) { + $table->integer('user_id')->unsigned(); + $table->integer('role_id')->unsigned(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + $table->primary(['user_id', 'role_id']); + //$table->foreign('user_id')->references('id')->on('users'); + //$table->foreign('role_id')->references('id')->on('roles'); + $table->index('user_id'); + $table->index('role_id'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('role_users'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/RolesTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/RolesTable.php new file mode 100755 index 0000000..9cef494 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/RolesTable.php @@ -0,0 +1,78 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\Sprinkle\Account\Database\Models\Role; +use UserFrosting\System\Bakery\Migration; + +/** + * Roles table migration + * Roles replace "groups" in UF 0.3.x. Users acquire permissions through roles. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class RolesTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('roles')) { + $this->schema->create('roles', function (Blueprint $table) { + $table->increments('id'); + $table->string('slug'); + $table->string('name'); + $table->text('description')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + $table->unique('slug'); + $table->index('slug'); + }); + + // Add default roles + $roles = [ + 'user' => new Role([ + 'slug' => 'user', + 'name' => 'User', + 'description' => 'This role provides basic user functionality.' + ]), + 'site-admin' => new Role([ + 'slug' => 'site-admin', + 'name' => 'Site Administrator', + 'description' => 'This role is meant for "site administrators", who can basically do anything except create, edit, or delete other administrators.' + ]), + 'group-admin' => new Role([ + 'slug' => 'group-admin', + 'name' => 'Group Administrator', + 'description' => 'This role is meant for "group administrators", who can basically do anything with users in their own group, except other administrators of that group.' + ]) + ]; + + foreach ($roles as $slug => $role) { + $role->save(); + } + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('roles'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/UsersTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/UsersTable.php new file mode 100755 index 0000000..a65eeed --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/UsersTable.php @@ -0,0 +1,69 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * Users table migration + * Removed the 'display_name', 'title', 'secret_token', and 'flag_password_reset' fields, and added first and last name and 'last_activity_id'. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class UsersTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('users')) { + $this->schema->create('users', function (Blueprint $table) { + $table->increments('id'); + $table->string('user_name', 50); + $table->string('email', 254); + $table->string('first_name', 20); + $table->string('last_name', 30); + $table->string('locale', 10)->default('en_US')->comment('The language and locale to use for this user.'); + $table->string('theme', 100)->nullable()->comment("The user theme."); + $table->integer('group_id')->unsigned()->default(1)->comment("The id of the user group."); + $table->boolean('flag_verified')->default(1)->comment("Set to 1 if the user has verified their account via email, 0 otherwise."); + $table->boolean('flag_enabled')->default(1)->comment("Set to 1 if the user account is currently enabled, 0 otherwise. Disabled accounts cannot be logged in to, but they retain all of their data and settings."); + $table->integer('last_activity_id')->unsigned()->nullable()->comment("The id of the last activity performed by this user."); + $table->string('password', 255); + $table->softDeletes(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + //$table->foreign('group_id')->references('id')->on('groups'); + //$table->foreign('last_activity_id')->references('id')->on('activities'); + $table->unique('user_name'); + $table->index('user_name'); + $table->unique('email'); + $table->index('email'); + $table->index('group_id'); + $table->index('last_activity_id'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('users'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Migrations/v400/VerificationsTable.php b/main/app/sprinkles/account/src/Database/Migrations/v400/VerificationsTable.php new file mode 100755 index 0000000..fa54da6 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Migrations/v400/VerificationsTable.php @@ -0,0 +1,57 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Migrations\v400; + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; +use UserFrosting\System\Bakery\Migration; + +/** + * Verifications table migration + * Manages requests for email account verification. + * Version 4.0.0 + * + * See https://laravel.com/docs/5.4/migrations#tables + * @extends Migration + * @author Alex Weissman (https://alexanderweissman.com) + */ +class VerificationsTable extends Migration +{ + /** + * {@inheritDoc} + */ + public function up() + { + if (!$this->schema->hasTable('verifications')) { + $this->schema->create('verifications', function (Blueprint $table) { + $table->increments('id'); + $table->integer('user_id')->unsigned(); + $table->string('hash'); + $table->boolean('completed')->default(0); + $table->timestamp('expires_at')->nullable(); + $table->timestamp('completed_at')->nullable(); + $table->timestamps(); + + $table->engine = 'InnoDB'; + $table->collation = 'utf8_unicode_ci'; + $table->charset = 'utf8'; + //$table->foreign('user_id')->references('id')->on('users'); + $table->index('user_id'); + $table->index('hash'); + }); + } + } + + /** + * {@inheritDoc} + */ + public function down() + { + $this->schema->drop('verifications'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/Activity.php b/main/app/sprinkles/account/src/Database/Models/Activity.php new file mode 100755 index 0000000..d5be589 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/Activity.php @@ -0,0 +1,86 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Activity Class + * + * Represents a single user activity at a specified point in time. + * @author Alex Weissman (https://alexanderweissman.com) + * @property string ip_address + * @property int user_id + * @property string type + * @property datetime occurred_at + * @property string description + */ +class Activity extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "activities"; + + protected $fillable = [ + "ip_address", + "user_id", + "type", + "occurred_at", + "description" + ]; + + /** + * Joins the activity's user, so we can do things like sort, search, paginate, etc. + */ + public function scopeJoinUser($query) + { + $query = $query->select('activities.*'); + + $query = $query->leftJoin('users', 'activities.user_id', '=', 'users.id'); + + return $query; + } + + /** + * Add clauses to select the most recent event of each type for each user, to the query. + * + * @return \Illuminate\Database\Query\Builder + */ + public function scopeMostRecentEvents($query) + { + return $query->select('user_id', 'event_type', Capsule::raw('MAX(occurred_at) as occurred_at')) + ->groupBy('user_id') + ->groupBy('type'); + } + + /** + * Add clauses to select the most recent event of a given type for each user, to the query. + * + * @param string $type The type of event, matching the `event_type` field in the user_event table. + * @return \Illuminate\Database\Query\Builder + */ + public function scopeMostRecentEventsByType($query, $type) + { + return $query->select('user_id', Capsule::raw('MAX(occurred_at) as occurred_at')) + ->where('type', $type) + ->groupBy('user_id'); + } + + /** + * Get the user associated with this activity. + */ + public function user() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsTo($classMapper->getClassMapping('user'), 'user_id'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/Group.php b/main/app/sprinkles/account/src/Database/Models/Group.php new file mode 100755 index 0000000..f10e066 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/Group.php @@ -0,0 +1,69 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Group Class + * + * Represents a group object as stored in the database. + * + * @package UserFrosting + * @author Alex Weissman + * @see http://www.userfrosting.com/tutorials/lesson-3-data-model/ + * + * @property string slug + * @property string name + * @property string description + * @property string icon + */ +class Group extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "groups"; + + protected $fillable = [ + "slug", + "name", + "description", + "icon" + ]; + + /** + * @var bool Enable timestamps for this class. + */ + public $timestamps = true; + + /** + * Delete this group from the database, along with any user associations + * + * @todo What do we do with users when their group is deleted? Reassign them? Or, can a user be "groupless"? + */ + public function delete() + { + // Delete the group + $result = parent::delete(); + + return $result; + } + + /** + * Lazily load a collection of Users which belong to this group. + */ + public function users() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->hasMany($classMapper->getClassMapping('user'), 'group_id'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/PasswordReset.php b/main/app/sprinkles/account/src/Database/Models/PasswordReset.php new file mode 100755 index 0000000..ac8a930 --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/PasswordReset.php @@ -0,0 +1,76 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Password Reset Class + * + * Represents a password reset request for a specific user. + * @author Alex Weissman (https://alexanderweissman.com) + * @property int user_id + * @property hash token + * @property bool completed + * @property datetime expires_at + * @property datetime completed_at + */ +class PasswordReset extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "password_resets"; + + protected $fillable = [ + "user_id", + "hash", + "completed", + "expires_at", + "completed_at" + ]; + + /** + * @var bool Enable timestamps for PasswordResets. + */ + public $timestamps = true; + + /** + * Stores the raw (unhashed) token when created, so that it can be emailed out to the user. NOT persisted. + */ + protected $token; + + /** + * @return string + */ + public function getToken() + { + return $this->token; + } + + /** + * @param string $value + */ + public function setToken($value) + { + $this->token = $value; + return $this; + } + + /** + * Get the user associated with this reset request. + */ + public function user() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsTo($classMapper->getClassMapping('user'), 'user_id'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/Permission.php b/main/app/sprinkles/account/src/Database/Models/Permission.php new file mode 100755 index 0000000..463af8d --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/Permission.php @@ -0,0 +1,121 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Permission Class. + * + * Represents a permission for a role or user. + * @author Alex Weissman (https://alexanderweissman.com) + * @property string slug + * @property string name + * @property string conditions + * @property string description + */ +class Permission extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "permissions"; + + protected $fillable = [ + "slug", + "name", + "conditions", + "description" + ]; + + /** + * @var bool Enable timestamps for this class. + */ + public $timestamps = true; + + /** + * Delete this permission from the database, removing associations with roles. + * + */ + public function delete() + { + // Remove all role associations + $this->roles()->detach(); + + // Delete the permission + $result = parent::delete(); + + return $result; + } + + /** + * Get a list of roles to which this permission is assigned. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function roles() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToMany($classMapper->getClassMapping('role'), 'permission_roles', 'permission_id', 'role_id')->withTimestamps(); + } + + /** + * Query scope to get all permissions assigned to a specific role. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $roleId + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForRole($query, $roleId) + { + return $query->join('permission_roles', function ($join) use ($roleId) { + $join->on('permission_roles.permission_id', 'permissions.id') + ->where('role_id', $roleId); + }); + } + + /** + * Query scope to get all permissions NOT associated with a specific role. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $roleId + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeNotForRole($query, $roleId) + { + return $query->join('permission_roles', function ($join) use ($roleId) { + $join->on('permission_roles.permission_id', 'permissions.id') + ->where('role_id', '!=', $roleId); + }); + } + + /** + * Get a list of users who have this permission, along with a list of roles through which each user has the permission. + * + * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough + */ + public function users() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToManyThrough( + $classMapper->getClassMapping('user'), + $classMapper->getClassMapping('role'), + 'permission_roles', + 'permission_id', + 'role_id', + 'role_users', + 'role_id', + 'user_id' + ); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/Role.php b/main/app/sprinkles/account/src/Database/Models/Role.php new file mode 100755 index 0000000..ce9cb8c --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/Role.php @@ -0,0 +1,105 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Role Class + * + * Represents a role, which aggregates permissions and to which a user can be assigned. + * @author Alex Weissman (https://alexanderweissman.com) + * @property string slug + * @property string name + * @property string description + */ +class Role extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "roles"; + + protected $fillable = [ + "slug", + "name", + "description" + ]; + + /** + * @var bool Enable timestamps for this class. + */ + public $timestamps = true; + + /** + * Delete this role from the database, removing associations with permissions and users. + * + */ + public function delete() + { + // Remove all permission associations + $this->permissions()->detach(); + + // Remove all user associations + $this->users()->detach(); + + // Delete the role + $result = parent::delete(); + + return $result; + } + + /** + * Get a list of default roles. + */ + public static function getDefaultSlugs() + { + /** @var UserFrosting\Config $config */ + $config = static::$ci->config; + + return array_map('trim', array_keys($config['site.registration.user_defaults.roles'], true)); + } + + /** + * Get a list of permissions assigned to this role. + */ + public function permissions() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToMany($classMapper->getClassMapping('permission'), 'permission_roles', 'role_id', 'permission_id')->withTimestamps(); + } + + /** + * Query scope to get all roles assigned to a specific user. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $userId + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForUser($query, $userId) + { + return $query->join('role_users', function ($join) use ($userId) { + $join->on('role_users.role_id', 'roles.id') + ->where('user_id', $userId); + }); + } + + /** + * Get a list of users who have this role. + */ + public function users() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToMany($classMapper->getClassMapping('user'), 'role_users', 'role_id', 'user_id'); + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/User.php b/main/app/sprinkles/account/src/Database/Models/User.php new file mode 100755 index 0000000..235f2ef --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/User.php @@ -0,0 +1,493 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Carbon\Carbon; +use Illuminate\Database\Capsule\Manager as Capsule; +use Illuminate\Database\Eloquent\SoftDeletes; +use UserFrosting\Sprinkle\Account\Facades\Password; +use UserFrosting\Sprinkle\Core\Database\Models\Model; +use UserFrosting\Sprinkle\Core\Facades\Debug; + +/** + * User Class + * + * Represents a User object as stored in the database. + * + * @author Alex Weissman (https://alexanderweissman.com) + * @property int id + * @property string user_name + * @property string first_name + * @property string last_name + * @property string email + * @property string locale + * @property string theme + * @property int group_id + * @property bool flag_verified + * @property bool flag_enabled + * @property int last_activity_id + * @property timestamp created_at + * @property timestamp updated_at + * @property string password + * @property timestamp deleted_at + */ +class User extends Model +{ + use SoftDeletes; + + /** + * The name of the table for the current model. + * + * @var string + */ + protected $table = 'users'; + + /** + * Fields that should be mass-assignable when creating a new User. + * + * @var string[] + */ + protected $fillable = [ + 'user_name', + 'first_name', + 'last_name', + 'email', + 'locale', + 'theme', + 'group_id', + 'flag_verified', + 'flag_enabled', + 'last_activity_id', + 'password', + 'deleted_at' + ]; + + /** + * A list of attributes to hide by default when using toArray() and toJson(). + * + * @link https://laravel.com/docs/5.4/eloquent-serialization#hiding-attributes-from-json + * @var string[] + */ + protected $hidden = [ + 'password' + ]; + + /** + * The attributes that should be mutated to dates. + * + * @var string[] + */ + protected $dates = [ + 'deleted_at' + ]; + + protected $appends = [ + 'full_name' + ]; + + /** + * Cached dictionary of permissions for the user. + * + * @var array + */ + protected $cachedPermissions; + + /** + * Enable timestamps for Users. + * + * @var bool + */ + public $timestamps = true; + + /** + * Determine if the property for this object exists. + * + * We add relations here so that Twig will be able to find them. + * See http://stackoverflow.com/questions/29514081/cannot-access-eloquent-attributes-on-twig/35908957#35908957 + * Every property in __get must also be implemented here for Twig to recognize it. + * @param string $name the name of the property to check. + * @return bool true if the property is defined, false otherwise. + */ + public function __isset($name) + { + if (in_array($name, [ + 'group', + 'last_sign_in_time', + 'avatar' + ])) { + return true; + } else { + return parent::__isset($name); + } + } + + /** + * Get a property for this object. + * + * @param string $name the name of the property to retrieve. + * @throws Exception the property does not exist for this object. + * @return string the associated property. + */ + public function __get($name) + { + if ($name == 'last_sign_in_time') { + return $this->lastActivityTime('sign_in'); + } elseif ($name == 'avatar') { + // Use Gravatar as the user avatar + $hash = md5(strtolower(trim( $this->email))); + return 'https://www.gravatar.com/avatar/' . $hash . '?d=mm'; + } else { + return parent::__get($name); + } + } + + /** + * Get all activities for this user. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function activities() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->hasMany($classMapper->getClassMapping('activity'), 'user_id'); + } + + /** + * Delete this user from the database, along with any linked roles and activities. + * + * @param bool $hardDelete Set to true to completely remove the user and all associated objects. + * @return bool true if the deletion was successful, false otherwise. + */ + public function delete($hardDelete = false) + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + if ($hardDelete) { + // Remove all role associations + $this->roles()->detach(); + + // Remove all user activities + $classMapper->staticMethod('activity', 'where', 'user_id', $this->id)->delete(); + + // Remove all user tokens + $classMapper->staticMethod('password_reset', 'where', 'user_id', $this->id)->delete(); + $classMapper->staticMethod('verification', 'where', 'user_id', $this->id)->delete(); + + // TODO: remove any persistences + + // Delete the user + $result = parent::forceDelete(); + } else { + // Soft delete the user, leaving all associated records alone + $result = parent::delete(); + } + + return $result; + } + + /** + * Determines whether a user exists, including checking soft-deleted records + * + * @deprecated since 4.1.7 This method conflicts with and overrides the Builder::exists() method. Use Model::findUnique instead. + * @param mixed $value + * @param string $identifier + * @param bool $checkDeleted set to true to include soft-deleted records + * @return User|null + */ + public static function exists($value, $identifier = 'user_name', $checkDeleted = true) + { + return static::findUnique($value, $identifier, $checkDeleted); + } + + /** + * Return a cache instance specific to that user + * + * @return \Illuminate\Contracts\Cache\Store + */ + public function getCache() + { + return static::$ci->cache->tags('_u'.$this->id); + } + + /** + * Allows you to get the full name of the user using `$user->full_name` + * + * @return string + */ + public function getFullNameAttribute() + { + return $this->first_name . ' ' . $this->last_name; + } + + /** + * Retrieve the cached permissions dictionary for this user. + * + * @return array + */ + public function getCachedPermissions() + { + if (!isset($this->cachedPermissions)) { + $this->reloadCachedPermissions(); + } + + return $this->cachedPermissions; + } + + /** + * Retrieve the cached permissions dictionary for this user. + * + * @return User + */ + public function reloadCachedPermissions() + { + $this->cachedPermissions = $this->buildPermissionsDictionary(); + + return $this; + } + + /** + * Get the amount of time, in seconds, that has elapsed since the last activity of a certain time for this user. + * + * @param string $type The type of activity to search for. + * @return int + */ + public function getSecondsSinceLastActivity($type) + { + $time = $this->lastActivityTime($type); + $time = $time ? $time : '0000-00-00 00:00:00'; + $time = new Carbon($time); + + return $time->diffInSeconds(); + } + + /** + * Return this user's group. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function group() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsTo($classMapper->getClassMapping('group'), 'group_id'); + } + + /** + * Returns whether or not this user is the master user. + * + * @return bool + */ + public function isMaster() + { + $masterId = static::$ci->config['reserved_user_ids.master']; + + // Need to use loose comparison for now, because some DBs return `id` as a string + return ($this->id == $masterId); + } + + /** + * Get the most recent activity for this user, based on the user's last_activity_id. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function lastActivity() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsTo($classMapper->getClassMapping('activity'), 'last_activity_id'); + } + + /** + * Find the most recent activity for this user of a particular type. + * + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + */ + public function lastActivityOfType($type = null) + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + $query = $this->hasOne($classMapper->getClassMapping('activity'), 'user_id'); + + if ($type) { + $query = $query->where('type', $type); + } + + return $query->latest('occurred_at'); + } + + /** + * Get the most recent time for a specified activity type for this user. + * + * @param string $type + * @return string|null The last activity time, as a SQL formatted time (YYYY-MM-DD HH:MM:SS), or null if an activity of this type doesn't exist. + */ + public function lastActivityTime($type) + { + $result = $this->activities() + ->where('type', $type) + ->max('occurred_at'); + return $result ? $result : null; + } + + /** + * Performs tasks to be done after this user has been successfully authenticated. + * + * By default, adds a new sign-in activity and updates any legacy hash. + * @param mixed[] $params Optional array of parameters used for this event handler. + * @todo Transition to Laravel Event dispatcher to handle this + */ + public function onLogin($params = []) + { + // Add a sign in activity (time is automatically set by database) + static::$ci->userActivityLogger->info("User {$this->user_name} signed in.", [ + 'type' => 'sign_in' + ]); + + // Update password if we had encountered an outdated hash + $passwordType = Password::getHashType($this->password); + + if ($passwordType != 'modern') { + if (!isset($params['password'])) { + Debug::debug('Notice: Unhashed password must be supplied to update to modern password hashing.'); + } else { + // Hash the user's password and update + $passwordHash = Password::hash($params['password']); + if ($passwordHash === null) { + Debug::debug('Notice: outdated password hash could not be updated because the new hashing algorithm is not supported. Are you running PHP >= 5.3.7?'); + } else { + $this->password = $passwordHash; + Debug::debug('Notice: outdated password hash has been automatically updated to modern hashing.'); + } + } + } + + // Save changes + $this->save(); + + return $this; + } + + /** + * Performs tasks to be done after this user has been logged out. + * + * By default, adds a new sign-out activity. + * @param mixed[] $params Optional array of parameters used for this event handler. + * @todo Transition to Laravel Event dispatcher to handle this + */ + public function onLogout($params = []) + { + static::$ci->userActivityLogger->info("User {$this->user_name} signed out.", [ + 'type' => 'sign_out' + ]); + + return $this; + } + + /** + * Get all password reset requests for this user. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function passwordResets() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->hasMany($classMapper->getClassMapping('password_reset'), 'user_id'); + } + + /** + * Get all of the permissions this user has, via its roles. + * + * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough + */ + public function permissions() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToManyThrough( + $classMapper->getClassMapping('permission'), + $classMapper->getClassMapping('role'), + 'role_users', + 'user_id', + 'role_id', + 'permission_roles', + 'role_id', + 'permission_id' + ); + } + + /** + * Get all roles to which this user belongs. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function roles() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsToMany($classMapper->getClassMapping('role'), 'role_users', 'user_id', 'role_id')->withTimestamps(); + } + + /** + * Query scope to get all users who have a specific role. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int $roleId + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeForRole($query, $roleId) + { + return $query->join('role_users', function ($join) use ($roleId) { + $join->on('role_users.user_id', 'users.id') + ->where('role_id', $roleId); + }); + } + + /** + * Joins the user's most recent activity directly, so we can do things like sort, search, paginate, etc. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeJoinLastActivity($query) + { + $query = $query->select('users.*'); + + $query = $query->leftJoin('activities', 'activities.id', '=', 'users.last_activity_id'); + + return $query; + } + + /** + * Loads permissions for this user into a cached dictionary of slugs -> arrays of permissions, + * so we don't need to keep requerying the DB for every call of checkAccess. + * + * @return array + */ + protected function buildPermissionsDictionary() + { + $permissions = $this->permissions()->get(); + $cachedPermissions = []; + + foreach ($permissions as $permission) { + $cachedPermissions[$permission->slug][] = $permission; + } + + return $cachedPermissions; + } +} diff --git a/main/app/sprinkles/account/src/Database/Models/Verification.php b/main/app/sprinkles/account/src/Database/Models/Verification.php new file mode 100755 index 0000000..cd5166d --- /dev/null +++ b/main/app/sprinkles/account/src/Database/Models/Verification.php @@ -0,0 +1,70 @@ +<?php +/** + * UserFrosting (http://www.userfrosting.com) + * + * @link https://github.com/userfrosting/UserFrosting + * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) + */ +namespace UserFrosting\Sprinkle\Account\Database\Models; + +use Illuminate\Database\Capsule\Manager as Capsule; +use UserFrosting\Sprinkle\Core\Database\Models\Model; + +/** + * Verification Class + * + * Represents a pending email verification for a new user account. + * @author Alex Weissman (https://alexanderweissman.com) + * @property int user_id + * @property hash token + * @property bool completed + * @property datetime expires_at + * @property datetime completed_at + */ +class Verification extends Model +{ + /** + * @var string The name of the table for the current model. + */ + protected $table = "verifications"; + + protected $fillable = [ + "user_id", + "hash", + "completed", + "expires_at", + "completed_at" + ]; + + /** + * @var bool Enable timestamps for Verifications. + */ + public $timestamps = true; + + /** + * Stores the raw (unhashed) token when created, so that it can be emailed out to the user. NOT persisted. + */ + protected $token; + + public function getToken() + { + return $this->token; + } + + public function setToken($value) + { + $this->token = $value; + return $this; + } + + /** + * Get the user associated with this verification request. + */ + public function user() + { + /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = static::$ci->classMapper; + + return $this->belongsTo($classMapper->getClassMapping('user'), 'user_id'); + } +} |