Like several others (http://drupal.org/node/1468334 and http://drupal.org/node/752386), I'm looking for a way to manipulate user-level flags on behalf of other users.

My use-case: I've created a content type for volunteer tasks and users can flag which tasks they're interested in helping with. I've also created a View that provides me with a list of all users who've flagged the different tasks (grouped by task, but not relevant for my question.)

What I'd like to be able to do is unflag users from this administrative view. Based on the two issue posts referenced above, I'm assuming this isn't possible at the present time...

If it *isn't* possible, I'd like to make this a feature request; there seems to be some interest in it. If it *is* possible, I'd love some guidance on how to make it work, even in a hack-ish form.

Thanks for the awesome work... this module has been helpful to me in the past in so many ways on so many different projects.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

cogno’s picture

The "Flag Clear" module looks promising, but I assume would take some reworking to make it D7 compatible and it appears to be abandoned. Maybe someone would be willing to make the necessary changes? (I'm a hopeless coder...)

quicksketch’s picture

I'm pretty positive I've already marked feature requests for this won't fix in the past. As you've found, it's not possible within Flag core and I don't plan on supporting it within the core module. The API is definitely capable of flagging on behalf of other users, but the messiness of the UI is going to be left to add-on modules.

joachim’s picture

Status: Active » Fixed

Sounds like this is fixed.

acrazyanimal’s picture

Status: Fixed » Needs review
FileSize
13.14 KB

I know you just changed this to fixed, but I was attempting to use the api to make user centric flag links that display on user pages, but could not get them to work. I had to patch the flag module to allow me, as an admin view and flag on behalf of other users. I've tested out the patch on a site and all seems to work well, but you'll have to let me know if you think I have missed something. I'm under some pressure today, but I will try and upload an example module that makes use of the new user context hook I've added to the api.

joachim’s picture

Status: Needs review » Postponed (maintainer needs more info)

> make user centric flag links that display on user pages

Could you explain in more detail what you were trying to do?

This patch looks like a lot of big changes and I don't really understand what it's giving us.

acrazyanimal’s picture

Sure!

Why create this patch?

@quicksketch mentions in #2 above:

The API is definitely capable of flagging on behalf of other users

but I found that wasn't entirely the case. If I want to build a contrib module that uses the api and flags on behalf of other users, there wasn't an effective way to create the links. Some of the key flag module functions assume the global user and don't provide a mechanism to pass in a user account. However, the flag_flag class object and children are more or less set up to accept accounts.

What was needed?

What this patch does is simply add extra functions and a hook to allow modules to set a context for the user account that is flagging. By default it will always use a passed in user account if one is provided, but will default back to the global user. However, a contrib module will be able to override the default by using hook_flag_user_context_alter(&$account, $flag, $content_id). The extra menu items I've added simply allow the flagging user id to be passed in the url for (un)flagging. This is the key change that allows other modules to maintain the user context when (un)flagging. None of the existing api's were changed and all the functionality should be the same.

An example:

Out of the box with the flag module I could use the api to create a module that puts a table of taxonomy term flags in a block on a user page. The problem was that admins on this particular site need to be able to see those user's choices and change their choices on behalf of the user. By assuming the global user by default the admins always saw their own choices and flagging always changed their own selections. By applying this patch I was able to add the flexibility necessary to set the user context for the flags to that of the user page rather then the global user.

Here is the code I needed in my contrib module to achieve this:

/* 
 * Flag hooks.
 */

/**
 * Implements hook_flag_link_types().
 */
function instant_notifications_flag_link_types() {
  return array(
    'usercentric' => array(
      'title' => t('User specific'),
      'description' => t('Make flag links user specific when on user profile pages. This allows admins to control and view flags of other users.'),
      'options' => array('usercentric_toggle' => TRUE),
      'uses standard js' => TRUE,
      'uses standard css' => TRUE,
    ),
  );
}


/**
 * Implements hook_flag_link().
 */
function instant_notifications_flag_link($flag, $action, $content_id) {
  $account = flag_get_user_flag_context($flag, $content_id);
  $token = flag_get_token($content_id);
  $link = array(
    'href' => 'flag/' . "$action/$flag->name/$content_id" . (($account->uid) ? "/$account->uid" : ''),
    'query' => drupal_get_destination() + array('token' => $token),
  );
  if (!empty($flag->usercentric_toggle)) {
    $link['attributes'] = array('class' => array('flag-link-toggle'));
  }
  return $link;
}


/**
 * Implements hook_flag_user_context_alter().
 */
function instant_notifications_flag_user_context_alter(&$account, $flag, $content_id) {
  if ($flag->name == 'instant_notifications_terms') {
    if (('user' == arg(0)) && (is_numeric($uid = arg(1)))) {
      $account = user_load($uid);
    }
  }
}


/**
 * Alter flag_form to add an option for the usercentric flag link type to
 * either use the built in AJAX toggle or not.
 */
function instant_notifications_form_flag_form_alter(&$form, &$form_state, $form_id) {
  $flag = $form['#flag'];
  $form['display']['link_options_usercentric'] = array(
    '#type' => 'fieldset',
    '#title' => t('Options for the "User Specific" link type'),
    // Any "link type" provider module must put its settings fields inside
    // a fieldset whose HTML ID is link-options-LINKTYPE, where LINKTYPE is
    // the machine-name of the link type. This is necessary for the
    // radiobutton's JavaScript dependency feature to work.
    '#id' => 'link-options-usercentric',
    '#weight' => 21,
  );

  $form['display']['link_options_usercentric']['usercentric_toggle'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use toggle?'),
    '#default_value' => isset($flag->usercentric_toggle) ? $flag->usercentric_toggle : TRUE,
    '#description' => t('Checked: make use of the flag module\'s built in AJAX toggle links. Unchecked: normal links will be used.'),
    '#access' => empty($flag->locked['usercentric_toggle']),
  );
}

Beyond this was simply the usual calls using the existing api to add links to a block to display the taxonomy term flags.

Let me know if you want any further particular details?

BTW: One of my favourite modules :)

joachim’s picture

Title: Manipulating per-user flags as admin » Manipulating per-user flags as another account
Version: 7.x-2.x-dev » 7.x-3.x-dev
Category: support » feature
Status: Postponed (maintainer needs more info) » Needs work

I think that creating your own link type and then having to tweak it in an alter hook is not the right way to go.

Surely it would be simpler if hook_flag_link() took an $account parameter?

acrazyanimal’s picture

Yes it would be simpler if hook_flag_link accepted an account parameter. I just didn't want to mess with your existing api. All modules that make use of it would have to be updated including flag_flag_link which does not encode an account parameter into its url.

Regardless there still remains the issue of allowing a module to define a context for the flagging user. The patch I provided is one way that I was able to accomplish this, but I am open to suggestions to make it work better and will put the effort in to make a committable solution.

joachim’s picture

> Yes it would be simpler if hook_flag_link accepted an account parameter. I just didn't want to mess with your existing api.

Well the change from 2.x to 3.x is the time to do it!

Let's add an optional $account parameter to hook_flag_link(), so we don't have to muck about with discovering context.

(And I am tempted to change it from a hook to a callback, but that's for another issue).

acrazyanimal’s picture

Cool, gotcha. It will definitely be more ideal to just be able to provide the $account variable. I'll try and have a second patch up for 3.x in a day or two.

Robin Millette’s picture

Before seeing this issue, here's what I did, with a bit of custom code:

#1804560: Allow administrators to change user flags

I'd like to make it a contrib module if it can't be integrated directly in the core module.

acrazyanimal’s picture

I've been meaning to re-roll the patch against 3.x, but haven't had time lately. I'll make a note to do that soon. Once its committed in 3.x there will still be the need to have a module that allows you to use flags in such a way. Like your proposed flag_manage module. Since flag 3.x is in alpha stage it makes sense to not even bother with a 2.x version. I don't see how it can be accomplished without altering the flag api to include the $account parameter; Perhaps there is a less invasive way, but @joachim made it fairly clear that the above method would not be committed in 2.x.

Robin Millette’s picture

I guess I should go ahead and clean up my code to publish it on drupal.org. I'll rename it to flag_manage, as you suggest. First will be support for flag 2.x (since that's my current use) and I'll launch a 3.x branch after that. It currently doesn't need any change to flag to work.

joachim’s picture

> I guess I should go ahead and clean up my code to publish it on drupal.org. I'll rename it to flag_manage, as you suggest.

Has that been done yet?

(BTW, I think flag_delegate might be a better name, maybe?)

See also a request for a VBO for doing this here #1468334: flag nodes on behalf of the users.

Robin Millette’s picture

VBO sounds good, but you really need auto-completion on users.

I haven't had time to move my code elsewhere, it only lives as a blog post for now, and it's customized for my case, where profile2 fields are use to auto-complete usernames: http://rym.waglo.com/node/252

flag_delegate sounds more ambitious, I would be fine with that, with an eye towards the future.

whastings’s picture

We also have a use case in which flagging on behalf of another user would be useful. We've added a view of flags to the user's account edit screen via Panels. Our goal is for both the user and admins to be able to view and flag/unflag flags on this page. But as things are, admins see and edit the flags based on their user accounts, not the account of the user they're editing.

Has there been any progress with either displaying a flag's state or flagging/unflagging a flag based on a user other than the one currently signed in? The only way we can see to make this happen would be to create our own flag link type and override the display of flags, as well as flagging and unflagging, to change the user they apply to. We'd rather not attempt this, as we believe it would be difficult to maintain.

I'd appreciate any help to relay to my team.

joachim’s picture

@16: Any progress would be reported here.

The simple answer is that there isn't any... this issue will progress when people who need this feature work on it. It sounds like your team could do that perhaps?

WorldFallz’s picture

Issue summary: View changes

just an fyi, https://www.drupal.org/project/flag_clear seems to work just fine.

sadashiv’s picture

Status: Needs work » Needs review
FileSize
8.73 KB

Hi,

I added a permission for admins. Users with this permission can flag/unflag on behalf of other users. Have modified views field to create flag/unflag link for user id from arguments or current user. I am using organic groups and message subscribe so have fixed and tested flagging with those modules and works fine.

I am attaching patch for these changes.

Hth,
Sadashiv.

Status: Needs review » Needs work

The last submitted patch, 19: Manipulating_per_user_flags_as_another_account-1473716.patch, failed testing.

sadashiv’s picture

Status: Needs work » Needs review
FileSize
8.75 KB

Have fixed the issue and resubmitting the patch.

Hth,
Sadashiv.

mgifford’s picture

Patch seems to apply nicely. What's the best way to test this?

sadashiv’s picture

I think the best way to test is directly hitting the url from browser and check whether flags get updated.

The syntax of url flag/ACTION/MACHINE_NAME/ENTITY_ID/USER_ID

Here
ACTION is either flag or unflat
MACHINE_NAME is the name of the flag
ENTITY_ID is the unique id of the entity which is flagged
USER_ID is a optional parameter. If passed then flags/unflags on behalf of the user. Logged in user needs to have permissions to set the flag value on behalf of other user.

I am using message_subscribe module so tested this using the UI provided by message_subscribe_ui module

Hth,
Sadashiv.

joachim’s picture

Status: Needs review » Needs work

Thanks for working on this!

Unfortunately, we've now started work on the D8 version of Flag. So really, this should be done on the 8.x branch first, and then backported. I'm loath to do that when this patch looks pretty good though -- I'll check with the other maintainer who's been doing the bulk of the D8 work.

  1. +++ b/flag.module
    @@ -636,10 +640,10 @@ function flag_form_user_admin_permissions_alter(&$form, &$form_state, $form_id)
    +    'href' => 'flag/' . ($flag->link_type == 'confirm' ? 'confirm/' : '') . "$action/$flag->name/$entity_id". ($uid != NULL ? "/$uid" : ""),
    

    Space needed either side of the . operator.

  2. +++ b/flag.module
    @@ -1568,12 +1573,13 @@ function template_preprocess_flag(&$variables) {
    -  $link = module_invoke($link_type['module'], 'flag_link', $flag, $action, $entity_id);
    +  $link = module_invoke($link_type['module'], 'flag_link', $flag, $action, $entity_id, $uid);
    

    This requires documentation.

  3. +++ b/includes/flag.pages.inc
    @@ -13,8 +13,19 @@
    +    if ($user->uid != $uid && !user_access('administer flaging')) {
    

    Typo in the permission name.

  4. +++ b/includes/flag.pages.inc
    @@ -13,8 +13,19 @@
    +      $flag->errors['flaging'] = t('You don\'t have permission to flag/unflag on behalf of other users.');
    

    Hmm that looks like it's going to work, but really, access should be done in an access callback.

  5. +++ b/includes/flag/flag_flag.inc
    @@ -1534,7 +1534,7 @@ class flag_flag {
    -  function theme($action, $entity_id, $variables = array()) {
    +  function theme($action, $entity_id, $uid = NULL, $variables = array()) {
    

    We can't change the signature for this function at this point, even if it's not entirely a true theme function it's going to be used by other people.

    The uid should probably go in the $variables.

  6. +++ b/includes/views/flag_handler_field_ops.inc
    @@ -58,6 +60,32 @@ class flag_handler_field_ops extends views_handler_field {
    +    foreach ($view_args as $key => $val) {
    

    I really prefer variables in a foreach to be given descriptive names. So here, $argument_id => $argument_handler.

Also, all the functions that gain a parameter need it documenting!

socketwench’s picture

That could be useful for 8.x. The patch would look really different, though.

Instead of providing a page handler, it might be easier to write the "flag delegation" page using views (since it's in core). Using views for this would make it more maintainable and duplicatable, and would provide an easy use case to test Flag's views integration.

joachim’s picture

AFAICT this D7 patch does that using views as well -- it adds options to the 'flag link' field so it can be set up to work with the flags of another user.

So shall we change the version on this issue to 8.x? I'm happy for updated patches for 7.x to get posted too.

sadashiv’s picture

I'll try to fix all problems with the patch as suggested at #24 and will resubmit the patch.

Thanks,
Sadashiv.

sadashiv’s picture

Status: Needs work » Needs review
FileSize
9.12 KB

Hi,

I tried to fix issues as suggested in #24. I am attaching a patch with the fix.

Hth,
Sadashiv.

joachim’s picture

Status: Needs review » Needs work

Good stuff.

Looks like points 2 and 6 in my last comment still need addressing though.

Also:

  1. +++ b/flag.module
    @@ -590,6 +596,10 @@ function flag_permission() {
    +      'title' => t('Administer flaging'),
    

    Typo here too.

  2. +++ b/flag.module
    @@ -590,6 +596,10 @@ function flag_permission() {
    +      'description' => t('Flag/Unflag on behalf of other users.'),
    

    Unflag should not be capitalized. Would probably be clearer to say something like "Flag and unflag items on behalf...."

sadashiv’s picture

Status: Needs work » Needs review
FileSize
9.12 KB

Hi,

I fixed those two issues.

Thanks,
Sadashiv.

sadashiv’s picture

Hi,

Have fixed all problems with the patch. Please review and update if the patch needs improvement.

Thanks,
Sadashiv.

rsbecker’s picture

I am using message_subscribe with the recently created subscribe_og module. I am able to see the view, but even if the user is already subscribed to receive email notifications from the group, the view shows the Send email flag, which is wrong. I confirmed this by adding the Flags Flagged field, which says the user is already flagged. If I click the Send email link I get a 403 error.

But I cannot figure out how to get the view to show the Unflag link.

Any suggestions here?

rsbecker’s picture

Any progress on this?

youfei.sun’s picture

After applying the patch, if you want to show a list of flag links which is pointing to different user, you can do something like this:

function HOOK_views_pre_render(&$view){
  if($view->name == 'SOME_VIEW_NAME'){
    foreach($view->result as $key => $row){
      //assuming you get a uid as a field in the view's row
      $uid = $row->YOUR_UID_FIELD;
      $entity_id = $row->THE_FLAG_ITEM_ENTITY_ID_FIELD;
      $flag_array = flag_get_user_flags('YOUR_FLAG_ENTITY_TYPE', $entity_id, $uid);

      $view->result[$key]->THE_FLAG_ITEM_ENTITY_UID_FIELD = $uid;
      $view->result[$key]->THE_FLAG_ITEM_ENTITY_ID_FIELD = isset($flag_array['FLAG_NAME']) ? $flag_array['FLAG_NAME']->entity_id : null;
      $view->result[$key]->flagging_flagged = $view->result[$key]->THE_FLAG_ITEM_ENTITY_ID_FIELD;
    }

  }
}

Note you have to also modify the css class to make the js functional, I'm figuring out how....it looks like the js part is kinda buggy when this patch is applied.

Yes this patch needs a lot of work.

sadashiv’s picture

Hi all,

I pulled the dev branch modified my previous patch to work with javascript toggle setting. Now it should work, note that we need to modify the view as well so that it works. I tried a fresh drupal install, and the entire message stack i.e. message, message_subscribe, message_subscribe_email, etc. I enabled the node subscribe_node and email_node flags and modified the view so that it works. I am attaching my subscribe_node_email so that you can import it (hopefully on a fresh instance) and configure your views accordingly.

Thanks,
Sadashiv.

benjamin.merkley’s picture

Was this ever ported over to D8? Saw some back and fourth about it?

sahaj’s picture

Also interested to see this in D8. Any chance?

Maedi’s picture

Was getting this notice in logs:

Notice: Undefined offset: 0 in flag_handler_field_ops->render() (line 197 of flag/includes/views/flag_handler_field_ops.inc)

There is a small bug where flag_handler_field_ops -> render() will still try to get the value of user_val when the views Flag link field is configured to "Logged in user". This should only happen when the Flag link is configured to get the user via "Contextual Argument".

The attached patch simply changes patch #36:

if ($uid == '') {

to:

if ($uid == '' && isset($this->options['user_option']) && $this->options['user_option'] == 'arg') {
sadashiv’s picture

Priority: Normal » Major

This is not reviewed for long time, Can anyone update that patch at 39 works, and please push this to core. Once it goes in d7, I can think of working on d8.

Thanks,
Sadashiv.

ron_s’s picture

I've spent a fair amount of time studying this patch (#39) and its use case.

While the support of a contextual argument for views is a great improvement, it does not fully meet the need of creating a single Views dashboard for managing various types of user flags. One of the ultimate goals for us (and I think for many who might want this type of functionality) would be to have a view where an admin can unflag entities regardless of who made the initial flag.

The attached patch helps to resolve this. It is a re-roll of #39 so it works cleanly against the current 7.x-3.x-dev, plus the addition of a third choice in the Views flag links: "Flagging user". This option allows for the selection of a uid field containing data of the user who originally performed the flagging. By having this data in each row, it is possible to regenerate the themed link so it mimics the URL that would be displayed to the user. Therefore an admin with the "administer flagging" permission can unflag entities acting as though they are in the role of the user that did the original flagging.

Please review and let me know if there are any questions. Thanks.

-----

As a side note, it seems one of the fundamental issues for managing flags in Views is the inability to use the flagging database table as the base table for creating a new view. If this was possible, it would ensure everything is keyed off of flagging_id rather than entity_id plus uid.

However, I don't think there is a meaningful way to resolve that in the current data model, since we cannot know the next flagging_id for a flag until the user has flagged an entity. The url for a flag has to be based on what is known at the given moment in time, which is <entity_id>/<uid>.

ron_s’s picture

One additional note, I noticed there were a variety of errors in Views due to the lack of a options_validate function. That was also included in patch #41. Thanks.

Status: Needs review » Needs work

The last submitted patch, 41: flag-change_user_flags_as_another_account-1473716-41.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

ron_s’s picture

Manually ran the same steps as the testFlaggingCreateException test that is causing a failure, but always returns an exception as expected. Not sure why it would be triggering a problem.

I've made a slight adjustment to the previous version's access function. Have also included an interdiff comparing patch #39 to the changes I have made.

See attached.

Status: Needs review » Needs work

The last submitted patch, 44: flag-change_user_flags_as_another_account-1473716-44.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

ron_s’s picture

Have no idea why the test is failing and cannot reproduce. If I attempt to run code where a user with authorization for a flag tries to run a flagging_save for a user that has no authority, it throws an exception. The test is saying it successfully saves the flagging entity.

If anyone has any insight I'd appreciate it. Maybe the test function needs some updates.

ron_s’s picture

Have investigated this further, and the problem seems to be with the following line that exists in previous versions of the patch in the access function:

if ($account->uid != $GLOBALS['user']->uid && !user_access('administer flagging')) {

The user created in the test script only has permissions to flag/unflag ($this->drupalCreateUser(array('flag test_flag', 'unflag test_flag'));), but running user_access('administer flagging') against this user always returns a TRUE result.

In patch #39, it gives the illusion that the test runs correctly because it skips the new condition, but in fact it is wrong there too.

mandclu’s picture

For anyone looking for this functionality for Drupal 8 / 9, I have created the Flag Assign User module.

Shenron_segamag’s picture

Is this issue still in the works ? I would be incredibly useful to be able to edit other users flags as an admin.