Unified support for managing relationships between users and events

Last modified: August 23, 2009 - 22:57

Note: this page is outdated.

The current state of affairs

Currently, there are a number of different contrib modules that manage the relationships between users and events:

Kieran made a nice table to compare event management modules

Unforunately, none of these modules works with the others, they all support slightly different means of representing the relationship between a user and the event, they all have slightly different features, and they're all (mostly) duplicate effort.

Our proposal

What we need is a unifying API that sits under all of these contrib modules that ties them together. In all cases, we just need to record the fact that there's a relationship between a given user (uid) and a given event (nid), and then store metadata about that relationship. Each contrib module can implement its own way to record a relationship (signup will create a form on the node view page, RSVP will use email, etc), and each one can implement its own way to display information about the relationship as it sees fit. But, at least most of the duplicate effort can be refactored into a common place, and all of the different methods for managing event attendance can work together (so if you reply to an RSVP email, your response will show up whenever the signup module is displaying attendance about an event).

Furthermore, the metadata that goes with the relationships must be flexible and admin-configurable. Different sites and different use cases demand different metadata. It's therefore a bad idea to attempt to make everyone agree on the same metadata and build that into the fundamental API and DB schema. However, there are some things that are fundamental to the relationship, which should be handled by this unifying API.

As an initial proposal, here's what I think this DB table needs to look like:

CREATE TABLE event_reply (
  uid int(10) unsigned NOT NULL default '0',
  nid int(10) unsigned NOT NULL default '0',
  reply_time int(10) unsigned NOT NULL default '0',
  reply int(2) unsigned NOT NULL default '0',
  UNIQUE KEY uid_nid (uid,nid)
);

I think all modules either already care (or should care) about when a user created their relationship to a given event (the "reply_time" field). I also believe all modules must care about what kind of relationship the user indicated. Support for yes, no, maybe, etc is very important for trying to manage attendance at any event. Certain modules attempt to provide functionality like noticing conflicts in a schedule (if you reply to multiple events happening at the same time and say you're coming to both), providing attendance limits, or even something basic like a printable attendance list. In all cases, the fundamental information about the reply is that a) the user replied at all and b) indicated whether they're planning to come or not. I believe a 2 digit int is better than a 1 bit bool, since it allows replies other than yes vs. no. At my site, I use a number from 0 to 10 (0 = no, 10 = definitely yes, anything else is something in between) and it seems to work great. For modules that don't care, or sites that don't care, they can only use 0 or 10, but it seems worth including something like this in the "core" event management API so that all contrib modules can agree on it and support it.

Other work to consider

Someone pointed out the User Related Content module. This might be a good basis for some of this user - event relationship management. I'll have to investigate that module and see if it's a suitable foundation, if there's chance of collaboration on that, etc.

There's a lot more to say, this is just an initial stab at generating some discussion and getting my ideas down.
-Derek

IRC discussion between dww and hunmonk

Chad (hunmonk) and Derek (dww) just had a nice discussion about this page. We generated a lot of new ideas. I'm posting the highlights here for further comment...

hunmonk: but i really don't know if the solution you proposed is workable
Derek: why not?
Derek: because each signup-related module is going to have diff metadata?
hunmonk: i think each module can have it's own kind of relationship
Derek: how so?
hunmonk: so you can't just say "this user is associated w/ this node"
hunmonk: or maybe i'm missing something
Derek: i'm proposing to think of it as "this user has a relationship to this node", where there are certain characteristics that are common to all kinds of relationships (the stuff in my event_reply table... needs a better name) and certain characteristics which can be module-specific (stored in another table, also keyed by uid + nid)
Derek: anything in the common table is shared, unified functionality across all such modules
Derek: i.e. the fact they replied at all, when they replied, and their basic response.
hunmonk: well there isn't much shared if both tables are keyed by uid/nid :)
hunmonk: plus, even times can be different, can't they? and status?
hunmonk: i don't see how this actually unifies anything
Derek: so, if you reply via an RSVP email, once the key fields go into event_reply, then the signup module would know about it, and would be able to display it on the event nodes, user profile, my fancy "user reply grid" (which you haven't seen yet), etc.
Derek: i think if you first reply via RSVP email, then change your status via signup, the entry in the shared table would be updated to reflect your most recent reply.
Derek: that's why it should be a shared, common table (imho)
Derek: (we could get crazy and get into the buisness of revisions for this, something i've wanted on my site... but that's another story)
Derek: even if it's all via signup, it'd be nice to see the initial reply, and then any modifications to the reply...
hunmonk: okay, so for workflows where mods want to work together, this would be helpful
Derek: yeah, that's one of the points... i think it's lame that if there are N different ways to say the same thing, you have to just choose 1 possible method and force everyone to use that.
Derek: or else none of the responses can be used by the event scheduler/organizer in a unified way.
hunmonk: i'm wondering about use cases where they might not work together, ie a user creating two different relationships to the node via two seperate mods
Derek: i maintain (perhaps incorrectly) that a user only has *one* possible relationship to a given event at any given point in time.
hunmonk: maybe.
Derek: if they change it, that's a new revision, sure, but there's no such thing as "i RSVP'ed maybe, but i signed up yes"...
Derek: if you did that, i think your *current* relationship should be "yes, as of [date_stamp]"
hunmonk: if we did revisions, i think we might want a different table structure
hunmonk: hm
Derek: yeah, i thought of revisions after i wrote that stuff...
hunmonk: event management is the _worst_.. :)
hunmonk: well, calendaring is the worst
Derek: that only came to me last weekend in the course of a 6 gigs in 3 days period where people kept changing their status which was driving me nuts...
Derek: i wanted a historical record of exactly who said what, when, who changed their mind, etc, etc, so i could do some historical blame-assignment. ;)
hunmonk: i actually won't make reply an int
hunmonk: just make it text
Derek: yeah, i was thinking of that.
hunmonk: if you want flexibility, that will give you more
Derek: i happen to dig my crazy mapping scheme, but i can see why not everyone would agree.
hunmonk: um
Derek: i suppose if it was text, i could do the reverse mapping in my own custom module to assign values and then provide these "attendance estimate" things.
hunmonk: so
Derek: however, i'm wondering about stuff like conflict resolution...
Derek: if it's just free-form text, it's harder to enforce any logic about comparing replies for the purpose of finding conflicts.
Derek: if there's an agreed-upon mapping of replies to what they mean, then there could be a conflict resolution module that knew what it was doing...
hunmonk: well it wouldn't be free form--you'd have states
...
hunmonk: events are nodes
hunmonk: wouldn't we be able to write the revision info?
hunmonk: meaning, use node revisions to track the history of the relationship
Derek: re: node revisions to track history... that'd only be if the *relationship* was itself a node (which might be a good idea)
hunmonk: yep
Derek: assuming there was a good way to view that node within other nodes (e.g. a table of "signups" when looking at a given event node.
Derek: yeah, if the relationship itself was a node, then we'd get all kinds of goodness for free...
Derek: it could be CCK, allowing people to easily define whatever metadata about the relationship they wanted
Derek: we'd get revisions for free
Derek: we'd get timestamps for free
hunmonk: so that feels like we're onto something
hunmonk: so that table would become "relate this event node to this relationship node to this user"
Derek: but, i'm a little leary of the viewing costs of such an approach...
Derek: but i guess that's where views come in. ;)
Derek: (i haven't played with those at all yet)
hunmonk: i haven't either
Derek: i also don't know how this fits in with broader node<->node relationship work...
hunmonk: unless there's a clear winner
hunmonk: i say we just pick an implementation and go with it :)
Derek: but, for example, i think it'd be slick as hell if there was a CCK field type for "relationship to another node" which allowed a flexible way to say what parts of that other node are displayed within the parent node...
Derek: currently, there's just a "make a link to some other node" field
Derek: which is better than nothing, but a little limited
Derek: and, it just assumes the "relationship" is a link, not itself a whole node full of metadata and other goodness
hunmonk: adrian mentioned per field permissions at one point as a CCK wish list item
hunmonk: hm. relationships as nodes.....
Derek: (should we move that part to #devel?)
hunmonk: i wonder if anyone has done that before
Derek: (get wisdom from others?)
...
Derek: let's unwind the stack...
Derek: replies as text, but not free-form...
Derek: what do you mean?
Derek: why is that better/different than ints (assuming we allow site admins to theme strings to go with the ints)
hunmonk: well
hunmonk: i see it as the drupal way of doing things for one
hunmonk: but in addition
hunmonk: i think it makes the code more readable
hunmonk: and i guess
hunmonk: it just seems to me that you get a good combination of flexibility and consistency, w/o some huge map of "1 means this, 2 means that..."
hunmonk: i'd rather see "confirmed", "unsure", etc
Derek: well, if it's truly flexible (admins can change the text however they want), then i don't see how any modules can agree on what the replies *mean*...
hunmonk: and i think any mod that wants to go outside the ten or so standard states can do so easily
Derek: (i personally don't care about scheduling conflict resolution stuff, but clearly you did when you wrote signup).
hunmonk: no, i didn't. i wrote that specifically for the vancouver conference site :)
Derek: ahh. ;)
hunmonk: ok
hunmonk: i see what you're saying
Derek: well, i can see why some people care about this as an important feature in scheduling functionality.
hunmonk: yeah
hunmonk: hm
Derek: so if i'm going to be blazing the field with a new, unified approach, i'd like to have a good answer for it, too...
hunmonk: i wasn't thinking that the states were admin determined
hunmonk: just text declared :)
Derek: i'm happy to go to 0-100, to allow more flexibility, but that just seems crazy.
hunmonk: still module determined, at least for the basic statets
Derek: also, keep in mind, i'm just talking about the 1 particular field that means "are you planning to be there?"
Derek: i can't honestly see how anyone needs more than 10 shades of grey for that. ;)
hunmonk: edge cases
hunmonk: it seems they always come up
Derek: all the other possible mojo about your relationship goes into other fields in your relationship node.
hunmonk: you brought some up you should know! :)
Derek: explain. ;)
hunmonk: there was some crazy thing you were wanting. i can't recall what it was
Derek: i see 1 edge as "i'm definitely not there", the other edge as "to the best of my knowledge, i'm definitely there", and having a few values in between for the wishy-washy people in the middle.
hunmonk: averaging out replies or something?
Derek: yeah, that's all accomplished by 0-10
Derek: for me, 0 = no, 10 = yes, 5 = maybe, etc.
Derek: and i just add this # up for all replies, and divide by 10
hunmonk: i'm not sure how many people would actually use that. hence the edge case designation :)
Derek: think of it as really being on a scale from 0 to 1 (maybe = 0.5), etc....
hunmonk: you're the only person who even suggested it
Derek: well, right, i don't know that people really need to use my "attendance estimate" average stuff...
Derek: however, i can definitely see value in 10 (err, 11) unique values a user can reply indicating the degree of attendance
Derek: then, for example, event_reply_conflicts.module can say if the reply is > [some config setting] i'll mark it as a conflict
hunmonk: sometimes this stuff makes my brain hurt :)
Derek: so, 0 is definitely not a conflict, and maybe 0-3 isn't, but anything 4-10 is considered a conflict
Derek: so, my int mapping scheme seems to solve (at least) two problems. ;)
hunmonk: as long as the only thing it represents about the attendance state is degree of certainty
Derek: plus, it'd be a way for the various modules to all speak the same language for this stuff... so if you replied "probably not" in the RSVP email, that'd still display as "probably not" in the signup table for the node.
hunmonk: i'm not sure if that's the only dimension we want to cover for attendance states
Derek: yeah, that's what i had in mind... attendance_certainty or something.
Derek: (should probably rename the field in the schema, if we can agree on this)
hunmonk: i don't agree
hunmonk: i think it's to specific
Derek: not to be a pain, but what's your alternative proposal, then? ;)
hunmonk: reply_state
hunmonk: textfield
hunmonk: look at project module
Derek: reply_state is fine. (i just said "reply" before, but sure, state is better).
hunmonk: you'd think it would be easy enough to come up w/ a standard list of issue states
hunmonk: but we just added three new ones not that long ago
Derek: right, but we're back to the orig problem... if there's no underlying mapping to something that can be handled in code, there's no way to, for example, do meaningful conflict resolution.
Derek: project issues are different...
Derek: they can be in a bunch of states, and those states have meaning
Derek: but those meanings are only used for selecting queries on the db to display the data
hunmonk: ok
hunmonk: so here's what i propose
hunmonk: it's a textfield
hunmonk: you have certain "standard" states that are documented
hunmonk: modules can talk between themselves using those
hunmonk: and you can still leave open the option of a module adding a new state if necessary
Derek: bold claim: the things you want to be able to add as new possible states are things that belong as new fields in the relationship metadata node, not as new possible values in the "reply_state" field.
hunmonk: perhaps
Derek: but, let's get concrete... got any examples of states people might want to set?
hunmonk: standard ones?
Derek: no, non-standard
hunmonk: hunmonk puts on creativity cap
•: "rain delay" :)
•: lol
Derek: here's the code from my custom version of signup.module i'm using: /** * Returns a string corresponding to the user's signup reply value * @ingroup signup_internal */ function _signup_reply_str($value) { switch ($value) { case '0' : return 'No'; break; case '3' : return 'Probably No'; break; case '5' : return 'Maybe'; break; case '7' : return 'Probably'; break; case '10' : return 'Yes'; break; default : return 'Unrecognized'; break; } }
Derek: (arg, that should have been more nicely formatted, sorry)
Derek: (it looks better in the code, i promise!) ;)
Derek: i don't even bother using all 11 states, since i don't really need them, but the math of 0-10 works so nicely, i decided to go for a sparse array...
hunmonk: i'm guessing there will be all kinds of creative ways that people will find to call something an 'event'
hunmonk: in which case standard states may not apply
hunmonk: i think that's the crux of it
Derek: (sort of off topic: i've flirted with the idea of having per-user mappings of these strings to ints, so that when the more unreliable people in my band say "probably", i only count that as a 3, not a 7, but that's another story...)
hunmonk: sheesh
hunmonk: see, the levels of complexity can be infinite :)
Derek: well, if they're not trying to schedule events, and they're trying to use our crap just as a way to do user->node relationships, they should just use a generic user->node solution, not all this (infinitely complex) crap. ;)
Derek: yeah, i know, it's crazy... i'm nuts about this stuff from years of dealing with flakey people in my band. ;)
hunmonk: no, i really mean that things can be seen as an event
Derek: (you might very well be onto something, but until you can produce an example for me to wrap my head around, i'm going to stick to my original position). ;)
hunmonk: what if people called a thunderstorm an event?
Derek: ahah! an example... phew!
hunmonk: that's certainly different than a rock concert :)
Derek: very true.
Derek: however, what does it mean that you're going to "signup" or "RSVP" for a thunderstorm?
hunmonk: anything that 'occurs' can be thought of as an event, really
Derek: true, but not anything that occurs can be scheduled.
hunmonk: that you're coming to my house to watch it?
Derek: then *that's* the event.
Derek: and that fits my model exactly.
Derek: it has a place, a time, and you have 0-10 possible "states" of if you're planning to attend.
hunmonk: okay
Derek: it's exactly like a rock concert. ;)
Derek: lol
hunmonk: how about signing up to take readings on it?
Derek: same deal: are you planning to go take measurements or not?
Derek: whole issue of trying to schedule events without a fixed time is a related question, that's the bigger issue i think you're trying to get at.
Derek: but that's just a whole new set of problems.
Derek: and i think that's more in the all-users-have-their-own-schedule, conflict resolution, voting on the best date/time kinda stuff.
hunmonk: if you go w/ attendance_certainty as an int, i'll bet you that we hit a limitation somewhere
hunmonk: but maybe it's enough for a start
Derek: call it reply_state if you like. ;) i just called it "reply" in my orig proposal.
hunmonk: i'd rather see it as a textfield
Derek: you've said that at least 3 times now, and each time you didn't have an answer to my concerns about that approach. ;)
hunmonk: i certainly did!
hunmonk: i said "documented standard states"
Derek: which users can't change?
hunmonk: that would allow modules to communicate at the code level
Derek: not in translation
hunmonk: ?
Derek: ints work better... let the code deal in ints (constants)
Derek: let the translation/theme folks worry about the strings displayed....
Derek: e.g. i can't strcmp("yes", $reply) if the email comes in with "si"
Derek: but, if the email gets processed and encoded as 10, then the code can compare $reply and 10, no sweat...
hunmonk: well
Derek: (i don't fully understand how drupal translation stuff works, but see what i'm getting at?)
hunmonk: well i'm not all that crazy about admins defining states
hunmonk: hm
hunmonk: hell i don't know
hunmonk: i need to think about it more
Derek: fair enough. i don't claim to have all the answers...
hunmonk: i think project uses int, and maps them to text strings
hunmonk: if you want user or admin created states, then i suppose int is the way to go
hunmonk: but we should get other opinions on this
hunmonk: i think we've made our mutual points clear enough
Derek: agreed, more opinions would be nice.

 
 

Drupal is a registered trademark of Dries Buytaert.