Not able to define BelongsToMany relationship using same models with different type - laravel-nova

I have Model Organization and User. There can be a buyer account manager and a seller account manager for an organization.
In organization the relationship is like :
public function managers() {
return $this->belongsToMany(User::class, 'organization_account_managers')->using('App\Model\Organization\OrganizationAccountManager')->withPivot(['account_manager_type']);
}
In User the relationship is defined as:
public function accounts()
{
return $this->belongsToMany(Organization::class, 'organization_account_managers')
->using('App\Model\Organization\OrganizationAccountManager')
->withPivot(['account_manager_type']);
}
When attaching in Nova, have defined on Organization as:
BelongsToMany::make('Account Managers','managers', 'App\Nova\User')
->fields(function () {
return [
Select::make('Type','account_manager_type')
->options(AppOrganization::$account_manager_types)
->rules('required')
->displayUsingLabels()->sortable(),
];
})
The table structure is:
Schema::create('organization_account_managers', function (Blueprint $table) {
$table->id();
$table->foreignId('organization_id');
$table->foreignId('user_id');
$table->tinyInteger('account_manager_type');
$table->timestamps();
});
Problem statement:
A user can be both buyer account manager and seller account manager. But when i try to attach so, NOva gives me an error: This users is already attached.
Appreciate any idea on how to resolve this.

From version v3.23.0 Laravel Nova allows duplicate relations.
BelongsToMany::make('Account Managers', 'managers', 'App\Nova\User')
->fields(function () {
...
})
->allowDuplicateRelations()
If you are using previous version you can try this workaround.

Related

ZF2 - ACL resources in a dynamic roles approach

Given a system with static permissions like posts.create, category.edit and such, and roles that can be created at runtime, both stored in a database but permissions can't (technically shouldn't) be modified; And the relations are N:M for users to roles and for roles to permissions:
Looking at the ACL package, at first sight it looks like I'd have to build up the ACL graph by querying my database roles on each request and adding them to the ACL instance and the allowed permissions like:
// Some class like AclService.php that should be called in Module.php
// ...
$roles = // query db for all roles and their permissions
foreach ($roles as $role) {
$acl->addRole($role->getName());
foreach ($role->getPermissions() as $permission) {
$acl->allow($role->getName(), null, $permission->getName());
}
}
Up to this point, in my controller's action (or a middleware, if they'd exist) I'd check if the user is allowed to execute the action:
// CategoryController
public function createAction() {
$user = // retrieve user from identity
if (! $acl->isAllowed($user->getRoles()->first(), null, 'categories.create')) {
// throw a 403 exception
}
}
What I don't get quite yet is, where does a Resource fits in this schema? Am I missing something here?
Or maybe are resources fit for when the permissions are not as granular as categories.create but just create?
You are using $acl->addRole($role->getName()); but as per the documentionation it should be defined in resources.
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Role\GenericRole as Role;
use Zend\Permissions\Acl\Resource\GenericResource as Resource;
$acl = new Acl();
$acl->addRole(new Role('guest'))
->addRole(new Role('member'))
->addRole(new Role('admin'));
$parents = array('guest', 'member', 'admin');
$acl->addRole(new Role('someUser'), $parents);
$acl->addResource(new Resource('someResource'));
$acl->deny('guest', 'someResource');
$acl->allow('member', 'someResource');
echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';
If this doesn't help then let me know I will try to help.

Grails find by property

Okay, I am trying to find all of my Employee that have a given role... However no matter what I try I end up getting the same exception thrown...
enum Role {
SFC("State Fitness Coordinator"),
TRAINING("Training"),
DFC("District Fitness Coordinator"),
final String longName
private Role(String longName) {
this.longName = longName
}
}
class Employee {
static hasMany = [roles: Role]
static constraints = {
}
}
The first Thing I tried was Employee.findAllByRoles(Role.DFC)
Then I tried:
Employee.findAll("FROM Employee e WHERE e.roles IN (:role)", [role: [Role.DFC]])
as well as
Employee.withCriteria {
'in'('roles', [Role.DFC])
}
all resulting in
Class
java.sql.SQLException
Message
Missing IN or OUT parameter at index:: 1
Any direction would be much appreciated.
with grails 2.3.8 and H2
Employee.findAll("FROM Employee e WHERE :role in elements(e.roles) ", [role: Role.DFC.toString()])
this works… even if I think that Role could be a real Domain simplifying all operations
I think the problem is that Role is an enum. Are you sure you want to make it an enum?
I recommend making it a class since new roles might be added. If so, you can easily add a record using bootstrap or SQL query without making a new build to production.
class Role {
String roleName
String description
}
In Bootstrap:
Role sfc = new Role("SFC","State Fitness Coordinator")
Role sfc = new Role("TRAINING," "Training")
Role sfc = new Role("DFC", "District Fitness Coordinator")
N.B. Please make sure you are not using spring security plugin which has its own 'Role' class. If so, please change the name of your 'Role' class to something like 'EmployeeRole'

GORM relational mapping

I have 3 domain classes User, Server, Quota and I want to map them with the following relations
A User can access many Servers with different Quotas
But it should not allow a User to access the same Server with different Quotas (or +Each User may have exactly one entry for each Server)
You can create a NxN relation between User and Server. However, will be necessary create a class for that relation. This is necessary because you need the attribute quota. In the standard way of a NxN relation Grails (Hibernate) doesn't create a class for it.
You'll need three classes:
User,Server,UserServer
Class UserServer {
int quota
static belongsTo = [user:User, server:Server]
static constraints = {user unique: 'server'}
}
The unique constraint it's very important, because as you said, a User may have exactly one entry for each Server.
To link and unlink a User and Server you can use the following methods:
Class UserServer {
int quota
static belongsTo = [user:User, server:Server]
static constraints = {user unique: 'server'}
static PackScheme link(User user, Server server) {
UserServer userServer = UserServer.findByUserAndServer(user, server)
if (!userServer) {
userServer = new UserServer()
user.addToUserServers(userServer)
server.addToUserServers(userServer)
userServer.save()
}
return userServer
}
static void unlink(User user, Server server) {
UserServer userServer = UserServer.findByUserAndServer(user, server)
if (userServer) {
user.removeFromUserServers(userServer)
server.removeFromUserServers(userServer)
userServer.delete()
}
}
}
Note that you need to create a hasMany relation in User and Server called userServers:UserServer.
This solution is based on this link: http://grails.org/Many-to-Many+Mapping+without+Hibernate+XML

How Do I Decide My Domain Model In This Case?

I need to develop a application for a user's management in a IT Project. This is done in order to learn Grails. I have some problem to start with :
In my sample app, a user has many tasks, belongs to a project, have many holiday status, belongs to the Resource planning and thats it. (kind of requirements!)
Now..... When it comes to domain modeling, how I actually model this? I came up the solution of modeling something like this :
class User {
//relationships. . . .
static belongsTo = [ company : Company, role : Role, resource : Resource]
static hasMany = [ holidays : Holiday, tasks : Tasks ]
Profile profile
Project project
String login
String password
static constraints = {
login(unique:true,size:6..15)
profile(nullable:true)
}
String toString() {
this.login
}
}
Now taking advantage of Grails scaffolding. I generated the view, hmmm well thats where I got struck!
With this model in place, clearly when creating a new User., I need to give away project details, resource details. Even though I can change the view as I need, for example I need only two fields say login and password for the new User to register my site. But as per data modeling, how I can handle other fields like Profile, Project and other relationships. This sounds complicated! I know i'm a newbie to both web development and I want your suggestions and how do I proceed with this?
Thanks in advance.
You need to override the save action in your controller and fill those additional fields there.
Try adding the following code in UserController:
def save = {
def userInstance = User.get(params.id)
if (!userInstance) {
userInstance = new User()
// here you can fill in additional fields:
userInstance.profile = myMethodToGetTheProfile()
userInstance.project = myMethodToGetTheProject()
...
}
userInstance.properties = params
if (userInstance.save(flush: true)) {
flash.message = message(code: 'default.created.message', args: [message(code: 'User.propertyName.label', default: 'User'), userInstance.id])}
redirect(action: session.lastActionName ?: "list", controller: session.lastControllerName ?: controllerName)
} else {
render(view: "form", model: [userInstance: userInstance, mode: 'edit'])
}
}
The implementation of methods to get the default project depends on your app's logic.

symfony - sfDoctrineGuard - restricting user creation based on group credentials

I am currently in the process of developing a fairly large and complex user management system using sfDoctrineGuard
I have created 4 groups, editors, moderators, admins and superadmins.
What I'm looking to do, is restrict certain users in the admin to be able to create/view/edit other users in the sfGuardUser admin module.
So for example a superadmins user can create editors, moderators, admins and other superadmins, but a moderator can only create editors.
Is this possible in sfDoctrineGuard, if so, could someone give me an insight on how I'd achieve this?
Thanks
First of all you can set credentials in generator.yml to show/hide links to actions and object actions based on credentials. For example:
config:
list:
object_actions:
_delete:
confirm: Вы уверены, что хотите удалить пользователя?
credentials: superuser
actions:
_new:
credentails: moderator
Next, configure your forms with custom table methods for doctrine choice widgets of groups:
class sfGuardUserForm extends PluginsfGuardUserForm
{
public function configure()
{
//groups_list
$this->getWidget('groups_list')->setOption('expanded', true);
$this->getWidget('groups_list')->setOption('table_method', 'getListForAdmin');
$this->getValidator('groups_list')->setOption('query', Doctrine::getTable('sfGuardGroup')->getListForAdmin());
}
}
class sfGuardGroupTable extends PluginsfGuardGroupTable
{
/**
* Builds list query based on credentials
*
*/
public function getListForAdmin()
{
$user = sfContext::getInstance()->getUser();
$q = $this->createQuery('g');
if (!$user->isSuperAdmin() && $user->hasCredential('moderator'))
{
$q->addWhere('g.name IN (?)', array('editor'));
}
else if ($user->hasCredential('editor'))
{
$q->addWhere('g.name IN (?)', array('editor'));
}
return $q;
}
}
A couple of enhancements: get rid of singletone call by passing user instance from action (in preExecute) and load group names form app.yml with sfConfig::get instead of hardcoding in it in code.

Resources