User Content Type creates a content type for users to be able to get their field-data or list them wherever only "node"-entities are available or allowed to use.

Features

  • User nodes get inserted, updated and deleted the same second users get inserted, updated or deleted.
  • Title and body of the user nodes can be customization in the module's configuration area.
  • Blocking a user unpublishes its node.
  • The connection to the node's original user can be found in the author of the user node.

Similar projects
There is one similiar project (usernode), but it is dead for some years now, was built for Drupal 4&5 only and can not be reused.

Project page of User Content Type
https://drupal.org/sandbox/MartinSchauer/2071679

Git
git clone http://git.drupal.org/sandbox/MartinSchauer/2071679.git user_content_type

Previous reviews

Reviews of other projects
https://drupal.org/node/2081543#comment-7869203
https://drupal.org/node/2083109#comment-7869785
https://drupal.org/node/2089695#comment-7869603

Thanks for reviewing!
regards Martin

Comments

PA robot’s picture

Status: Needs review » Needs work

There are some errors reported by automated review tools, did you already check them? See http://pareview.sh/pareview/httpgitdrupalorgsandboxMartinSchauer2071679git

We are currently quite busy with all the project applications and we prefer projects with a review bonus. Please help reviewing and put yourself on the high priority list, then we will take a look at your project right away :-)

Also, you should get your friends, colleagues or other community members involved to review this application. Let them go through the review checklist and post a comment that sets this issue to "needs work" (they found some problems with the project) or "reviewed & tested by the community" (they found no major flaws).

I'm a robot and this is an automated message from Project Applications Scraper.

kasalla’s picture

Hi,

first, the git link in your first post is your personal git link, please provide the public one:
git clone http://git.drupal.org/sandbox/MartinSchauer/2071679.git user_content_type

user_content_type.module
--------------------------------------

  • You store many variables in the database because you use the system_settings_form(); Create a .install file and provide a hook_uninstall to delete the stored variables.
  • line 157 and 369: in db_query the 'user' value should be a placeholder. Use the arguments array for this function.

the other code looks good.

Kind regards
kasalla

Martin Schauer’s picture

Issue summary: View changes

Added pareview as a previous revision.

Martin Schauer’s picture

Status: Needs work » Needs review

Thanks kasalla for the review!

I changed the git link, added an install-file with an uninstall-hook to clear the variables and remove the craeted content type on uninstall and cleaned my db-query-calls.

I also cleaned the code following coder's and pareview's automated review again, so the format should fit Drupal's coding-conventions as well.

regards,
Martin

mac_weber’s picture

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

How this is different from user profiles?
I don't see any point on having user as nodes, as users can be managed via profiles.
Moreover, user profiles CAN be handled by Views!

Martin Schauer’s picture

Are you talking about a specific module called "user profiles" or something I don't know about? If not, users can be managed via profiles and can be handles by views of course, but for example listing them together with other content types in one view is extremely limited. With this module you can handle them as a content type and therefore select eg. "news", "events" and "users" and list them on one map (or any other view-type) and even make them filterable for users by one exposed filter without any further customization.

This example can be seen in action on the activity map on EIP Water's start page.

In some situations users are nothing but additional content of a page and therefore need to be treated as content as well.

regards, Martin

Martin Schauer’s picture

Status: Postponed (maintainer needs more info) » Needs review
mac_weber’s picture

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

@Martin sorry I don't see limitations on using users in Views. Can you explain it better?

For example: if you need a view listing users you can just create it by setting Show: Users on the View create form.

Another example: if you are listing content and you need extra information about the user, you can use Views relationships. Relating the content with the users will display all the user fields or any other information available on creating a view as in the first example.

mac_weber’s picture

@Martin I took a better look at your example and now I think I understand what you are trying to accomplish. In the website you sent they are listing different node types (not sure if it is really node types) as map layers. In addition, there is also users in this listing.

The problem there is listing different types of entities. By default when you create a view you need to choose a type, such as content, users, files, etc...

I don't think switching the user profiles to nodes is the best approach here. The reason is that later you may need to list other different entities and duplicating these entities as nodes would not be the best practice. Moreover, you will lose a lot of functionalities if you handle users as nodes, besides some problems it may bring later to your project.

The best thing to do it to research how to list different entity types in the same view. This way you will keep all good things that all these different entities offer. I've never done such thing, but I'd be interested on how this can be done.

Martin Schauer’s picture

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

I don't think switching the user profiles to nodes is the best approach here. The reason is that later you may need to list other different entities and duplicating these entities as nodes would not be the best practice. Moreover, you will lose a lot of functionalities if you handle users as nodes, besides some problems it may bring later to your project.

The thing here is that the user content type does not replace the user itself. As a site developer, site admin etc. you have the choice of which entitiy-type to use for which use case.

The best thing to do it to research how to list different entity types in the same view. This way you will keep all good things that all these different entities offer. I've never done such thing, but I'd be interested on how this can be done.

Exactly this research was my intention to develop this module, because in fact there is no clean, unhacky way of listing different entity types in one view. By solving this problem the way this module does it, not only views get rid of that problem but also any other module that is limited on the entity type (may it be "only one entity type" or "only node-entities").

Of course this module will not handle every single use case, but I had quite some use cases in my past projects where it fit perfectly and I never faced any problems, so I thought about giving others the possibility to use it as well. The way this module currently works will maybe change in the future, depending on the incoming issues and ideas of other users, but since this module will get maintained actively I am quite optimistic about developing a good solution here.

regards,
Martin

mac_weber’s picture

@Martin, the solution you are proposing leads to more problems because if the admin chooses to use the user node he will have to manage the duplicated entries. Believe me, this is a big problem you don't want on your site.

You better solve it as proposed here: http://drupal.stackexchange.com/questions/25306/how-do-i-create-a-view-o...

The description of the issue is very similar to the example you had pointed.

I haven't searched for modules that can do it. If you cannot find I think you should change your strategy and do it in a generic way that other people in need to list different entities will also benefit from your project.

greggles’s picture

@mac_weber - I don't think your reviews so far have really followed the project application review guidelines. Your insight and feedback is helpful, but it would be easy to read comment #10 as an requirement rather than a suggestion and I think it should be a suggestion. In my opinion it's very reasonable to want a node per user. There may be reasons why this creates problems, but for certain sites I can see how it would be a reasonable solution. I don't see this as a performance/administrative/security issue. It's an architectural choice which is not relevant to project application process EXCEPT that the pros/cons of this approach should be documented.

mac_weber’s picture

@greggles you read my comments correctly. I really see this approach as a performance/administrative/security issue and also a bad practice.

Nodes are not designed to be used as users. You cannot do access control on user-nodes, for example. Having duplicates of real users and user-nodes leads to *many* administrative problems.
This way the system cannot get:

  • User language
  • User access control
  • User password retrieval
  • User profile links (duplicated with real user and user-nodes)
  • Many many other things defined at $user and/or controlled using it

Any modules that depends of something about users rely on $user. Using such approach means these modules get broken in systems that implement user-nodes. My biggest concern is access control, but as I said, it is not the only critical thing affected here.

mac_weber’s picture

Status: Needs review » Needs work

I had a chat with @greggles and he convinced me that this is not a performance/administrative/security problem as long it is explained how this module is intended to be used and in fact for some projects it may a feature, not a bug =)

However, there are other problems:
http://drupalcode.org/sandbox/MartinSchauer/2071679.git/blob/refs/heads/...

 $node->title .= ((isset($user->{$title_field_1}) && !empty($user->{$title_field_1}) && isset($user->{$title_field_1}[LANGUAGE_NONE][0]['value'])) ? $user->{$title_field_1}[LANGUAGE_NONE][0]['value'] : '');

There are other problems like this
Read: https://drupal.org/coding-standards#linelength

Control structure conditions should also NOT attempt to win the Most Compact Condition In Least Lines Of Code Award™

http://drupalcode.org/sandbox/MartinSchauer/2071679.git/blob/refs/heads/...

drupal_set_message(check_plain(t('Successfully added the content type "User" and @count user-nodes.', array('@count' => $user_add_count))));

Read: https://api.drupal.org/api/drupal/includes%21common.inc/function/t/6
(The docs for D7 for this function are not so good as for D6)
You should not run check_plain() on t(). Just using @variable is enough and t() will take care of it.

.
http://drupalcode.org/sandbox/MartinSchauer/2071679.git/blob/refs/heads/...
function _user_content_type_node_create() and many other functions need @param comments for its arguments.
Read: https://drupal.org/coding-standards/docs#param

Martin Schauer’s picture

@Mac_weber:
Thanks a lot for your detailed tips!

I did my best to get rid of all the problems you mentioned and added documentation to the functions where it was missing.

I'm glad you see the use of this project now. I think a "possible errors when using this module"-list could be helpful anyway indeed (added this to my todo-list).

Thanks again!

regards,
Martin

Martin Schauer’s picture

Status: Needs work » Needs review
greggles’s picture

Status: Needs review » Needs work

The code on http://drupalcode.org/sandbox/MartinSchauer/2071679.git/blob/refs/heads/... should ideally use format_plural so that the noun can match the count of items (in case there is only 1 node created, for example).

Martin Schauer’s picture

Status: Needs work » Needs review

@greggles:
Thank you for this tip!
I updated the code to use format_plural() now.

regards,
Martin

asherry’s picture

@Martin, just a thought, are you using the location module for the actual coordinates? The location_entity module has views handlers to let you create a view of location entities directly. If you're location_cck to connect a location to a user, I don't think there is a built in relationship handler for that in the location module, but that wouldn't be that difficult to do as a contrib project.

Long term that might be a better solution to include any entity on your map, Redhen contacts, relations, taxonomy, etc.

a_thakur’s picture

// Content type exists, delete it.
if (isset($contenttypes['user_node'])) {
  // Delete all content.
  $user_nodes = node_load_multiple(array(), array('type' => 'user_node'));
  foreach ($user_nodes as $user_node) {
    node_delete($user_node->nid);
  }

Since you just need nid here, so node_load_multiple() would be an expensive operation. It would be better to use db_select() instead.

  $nids  = db_select('node', 'n')
    ->fields('n', array('nid'))
    ->condition('type', 'user_node')
    ->execute()
    ->fetchCol();
  node_delete_multiple($nids);
Martin Schauer’s picture

@asherry:
In this case a country-taxonomy with latitude- and longitude-fields (fetched via feeds) was used (for some reasons but mainly to provide reliability in this simple use-case). But in a more complex use-case, where location has to be used, you are right, but there still are 3 questions left that I would have to think about:

- Do it want to get limited by location's view-handlers?
- Do I want to use node's title- and body-fields but still include users without any hooks or hacks?
- And the most important question: Will maps or views be the only place where I want to display different entity-types together (it's not always about the the location)

But of course, if you only want to display different kinds of entities (maybe not only nodes and users) on one map, your solution would be the more proper and clean one.

@a_thakur:
You are totally right!
I replaced the mentioned code, thank you for this tip.

mac_weber’s picture

Status: Needs review » Reviewed & tested by the community

@Marting change the README to explain "to be able to handle them as nodes." It is misleading, as the user-nodes will be used only for listing the users, not to handle them. They should not be used, for example, to get the language of this user. I think this was one of the main reasons I was opposing to this module, as I was thinking on it as a way to really handle users.

Moving it to RTBC, as it's a minor change you can easily fix.

a_thakur’s picture

@Martin Schauer

There is a similar occurence of the code in .install file as well: Line #17 to Line #20. This can be changed as well.

Martin Schauer’s picture

@Mac_Weber:
I changed the passage in the README.txt, so it should not be misunderstood anymore.

@a_thakur:
Thank you for advising me of this, these lines are fixed now as well.

mac_weber’s picture

@Marting read https://drupal.org/coding-standards#linelength

You can make conditionals look simpler at function _user_content_type_update_fields(): http://drupalcode.org/sandbox/MartinSchauer/2071679.git/blob/refs/heads/...

Martin Schauer’s picture

@Mac_Weber:
I have already read that paragraph of the coding standards, but in my opinion it is really not necessary to make the conditions you mentioned any simpler. I only check if the user has data for a field and added comments to make it even clearer, no complexity at all.

regards,
Martin

mac_weber’s picture

@Martin the problem is not how complex it is, but it is a very long line which you can shorten by using tokens as in the example:

The logic is the same simple logic, but do you see difference on the readability of the code? It helps other people to understand and contribute to your module in the future.

/**
 * DON'T DO THIS!
 */
  if ((isset($key) && !empty($user->uid) && $key == $user->uid) || (isset($user->cache) ? $user->cache : '') == ip_address() || isset($value) && $value >= time())) {
    ...
  }
/**
 * DO DO THIS!
 */

// Key is only valid if it matches the current user's ID, as otherwise other
  // users could access any user's things.
  $is_valid_user = (isset($key) && !empty($user->uid) && $key == $user->uid);

  // IP must match the cache to prevent session spoofing.
  $is_valid_cache = (isset($user->cache) ? $user->cache == ip_address() : FALSE);

  // Alternatively, if the request query parameter is in the future, then it
  // is always valid, because the galaxy will implode and collapse anyway.
  $is_valid_query = $is_valid_cache || (isset($value) && $value >= time());

  if ($is_valid_user || $is_valid_query) {
    ...
  }
Martin Schauer’s picture

@Mac_Weber:
Okay, you are right. I enhanced the readability of my longer conditions now, e.g.:

if (!empty($title_field_1)) {
  // User has data for this field.
  $field_exists = (isset($user->{$title_field_1}) && !empty($user->{$title_field_1}));

  // This field has an actual value, not only a reference to anything
  // else (e.g., a taxonomy term). To be expanded in the future.
  $field_has_value = (isset($user->{$title_field_1}[LANGUAGE_NONE][0]['value']));

  if ($field_exists && $field_has_value) {
    $node->title .= $user->{$title_field_1}[LANGUAGE_NONE][0]['value'];
  }
}

regards,
Martin

Martin Schauer’s picture

Issue summary: View changes

Changed the personal git-link to the public one.

mac_weber’s picture

Good job Martin!

mac_weber’s picture

Issue summary: View changes

Replaced the project's short-definition with a better one.

Martin Schauer’s picture

Issue tags: +PAreview: review bonus

Added "PAReview: review bonus"-tag

klausi’s picture

Status: Reviewed & tested by the community » Fixed

manual review:

  1. the project page should also mention the profile2 module as similar module.
  2. "'#empty_option' => '- No data -',": all user facing text must run through t() for translation. Also elsewhere like "'#value' => 'Delete user content',". Please check all your strings.
  3. user_content_type_uninstall() duplicates _user_content_type_delete_all()? Why don't you call it from there?
  4. _user_content_type_update_fields(): code duplication for the 3 fields. Can't you just walk through them in a loop?
  5. user_content_type.module: I would suggest to move the page callback to a separate include file to keep the module file short.
  6. _user_content_type_build_all(): this will not scale if a site has many users, the page request will just die with a PHP timeout. You should mention on the triggering button that it will only work for small sets of users. A better way is the batch API to work through larger sets.
  7. _user_content_type_build_all(): why do you have to delete everything first? That is quite a waste and will break existing links to the user nodes.
  8. Not sure if this should live in the existing usernode project or not - but I guess this is sufficiently different.

Not application critical application blockers, so ...

Thanks for your contribution, Martin Schauer!

I updated your account so you can promote this to a full project and also create new projects as either a sandbox or a "full" project.

Here are some recommended readings to help with excellent maintainership:

You can find lots more contributors chatting on IRC in #drupal-contribute. So, come hang out and stay involved!

Thanks, also, for your patience with the review process. Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

Thanks to the dedicated reviewer(s) as well.

Martin Schauer’s picture

Thanks a lot for the detailed review and the updating of my account!

  1. the project page should also mention the profile2 module as similar module.
    Added that module to the list of similar modules.
  2. "'#empty_option' => '- No data -',": all user facing text must run through t() for translation. Also elsewhere like "'#value' => 'Delete user content',". Please check all your strings.
    Added translation for all the strings I missed.
  3. user_content_type_uninstall() duplicates _user_content_type_delete_all()? Why don't you call it from there?
    Added a call to module_load() and the already existing function _user_content_type_delete_all().
  4. _user_content_type_update_fields(): code duplication for the 3 fields. Can't you just walk through them in a loop?
    Actually I don't know why I did it like that... replaced the current approach for the title-builder to a single loop on updating the field-data and creating the form-fields in the admin-form.
  5. user_content_type.module: I would suggest to move the page callback to a separate include file to keep the module file short.
    Moved the creation of the admin-settings-form to an independent file, the other functions are needed here I guess.
  6. _user_content_type_build_all(): this will not scale if a site has many users, the page request will just die with a PHP timeout. You should mention on the triggering button that it will only work for small sets of users. A better way is the batch API to work through larger sets.
    Thank you for this tip! I am using the batch API for the creation of the full set of user-nodes now.
  7. _user_content_type_build_all(): why do you have to delete everything first? That is quite a waste and will break existing links to the user nodes.
    I worked over the whole process of inserting, updating and deleting in this module. Nids stay the same now (as long they don't get deleted manually) and overall modifying user-fields works a lot better now.
  8. Not sure if this should live in the existing usernode project or not - but I guess this is sufficiently different.
    I will talk to fago about this, but I think referencing each other is a good start here.

See you in Prague next week!

regards,
Martin

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

Added reviews of other projects