Closed (fixed)
Project:
Privatemsg
Version:
6.x-1.x-dev
Component:
Code
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
28 Jul 2008 at 15:53 UTC
Updated:
23 Apr 2009 at 20:32 UTC
Jump to comment: Most recent file
Comments
Comment #1
litwol commentedThats on the to do list.
Comment #2
aexchecker commentedA simple
^-^
Comment #3
naheemsays commentedwhy not just call the pm_send function?
Comment #4
jose reyero commented@nbz
Yes, I know we could use that one, and also just populate the database, which would take little more work.
What I'm asking here though is a simple API function that can be used by this one or other modules without needing to worry about privatemsg module internals.
Comment #5
berdirJust thinking out loud...
Of course, there needs to be a send privatemsg api function, the signature could look like similiar to the one postet above, for example:
function privatemsgapi_send($title, $body, $recipients, $author = NULL)
- What does $recipients contain ? ID's, Strings, user objects ? => how intelligent should the function be ?
- I don't think we need a $thread_id, answering a existing thread doesn't need $title nor $recipients imho, as we don't want to allow to change this information. (Simply because the module is unable to handle something like this at this time... See the discussion in #324389: Show author(s) when viewing inbox), perhabs provide another, simplified function for answering an existing thread:
function privatemsgapi_answer($thread_id, $body, $author = NULL)
- If $author is null, then use global $user
- What about other interactions... ? delete, set_read, load... ?
- And, we need a hook to inform other modules about changes in a thread/message (notifications etc.) => only inform or do we want to give them the possibility to change the message?
function hook_privatemsg_alter(&$message, $action, $owner)
- $message is an array containing all information of the message that is currently "worked on" => does not integrate nicely with the api calls, any other ideas ?
- $action is clear, possible values (this does have influence on the contents of $message): new, answer, delete, read (?), for answer/new we could also provide before and after actions (on after we do know things like mid, timestamp and thread_id, before would allow to change the message
- $owner is the current user... the autor, the reader, the one whose message gets deleted (doesn't need to be the current user)
Ideas, feedback ?
Comment #6
naheemsays commentedAlso thinking out aloud
I think we are moving towards using the full object. It saves other modules from having to reload any user data when they hook into processes.
As for scope or what to do, I have no idea.
A good way to decide what is needed may be to alter pm_send to pass data to "privatemsgapi_send". That should give an idea as to what is needed.
We do need a $thread = NULL in there, and maybe a way to pass additional variables that are not central to privatemsg, or we have not thought of yet. I would prefer if there was a single function that could be called for as many reasons as possible - why have two apis, one for a new message and another for a reply?
PS if there is ever a need to prefer no threading, the current module can be allowed very easily to allow that. Just put the thread info inside an if check for a variable. if a thread_id is not passed along, the module will create a new thread.
Comment #7
berdirI think there is one reason for splitting up the api calls -> Making code more understandable. If we have one method for "everything" we end up with something like the following if we answer an existing thread:
privatemsgapi_send(null, $body, array(), null, $thread_id);This is exactly what webchick talked about at http://webchick.net/6-pass-patch-reviews (pass 2).
Another approach would be the use of an array.
privatemsgapi_send($message);The advantages are that it is very flexible and would already be in the right form for my proposed hook function. And array-parameters are somewhat "usual" in drupal... menu, fapi and so on. It would however need very clear documention (if thread_id is empty it starts a new thread and so on) while privatemsgapi_send($title, $recipients, $body) is quite self-speeking.
And yes, user objects are probably the best way, the only problem could be memory consumption (if a module provides a send to all function on a big site, for example)
Comment #8
berdirOk, here is what I currently have as a patch. The functions are currently in privatemsgapi.inc, but can easily be moved to privatemsg.module.
- There are two levels of abstraction. Easy-usable functions for other modules to create threads and answer on them and an internal function that does the actual sending
- Internal: _privatemsg_send($message). This is more or less a copy of the current pm_send() function, it simply takes the array, calls some hooks and inserts the data into the db. No validation or whatsoever is done in here. In a second step, pm_send can be rewritten to use this function. The main difference between them is that _privatemsg_send does not output anything while pm_send would call _privatemsg_send() and add a message indicating that the message was sent.
- Top-Level: privatemsg_new_thread($subject, $body, $recipients, $author = NULL) and privatemsg_answer($thread_id, $body, $author = NULL). These functions validate the message, create a array and call _privatemsg_send. privatemsg_answer does also read the subject and recipients from the selected thread.
- privatemsg_get_link($recipient, $account = NULL): This function does return a link which can be used by url/l to generate a link. It does *not* use l itself because it's impossible to be flexible enough, see http://drupal.org/node/326979#comment-1111420
- Hooks: I'm currently using the presave, insert and validate hooks I already described at #350601: Creating a hook, allowing other modules to add functionality
Open/Next things to work on...
- Generic review of the current code...
- Are there additional functions/hooks we need? Probably delete...
- Maybe supporting multiple recipients for privatemsg_get_link (privatemsg_new would need to be changed too..)
- Rewrite privatemsg.module to use _privatemsg_send, validation hook and so on...
- ...
Comment #9
litwol commentedDo we really need different functions for new thread and reply and message send? i'm not sure we want to force other developers decide which one to use. i think all message sending interface should be done (if at all possible) through a single send function and then privatemsg.module would then figure out if its a reply or a new thread or what ever.
Comment #10
berdirHm..
I am not sure about this. Actually, I'm not even sure if we need the possibility to answer existing threads via an api call at all. But if we do, a separate function is imho better, because of the following reason:
We could also add an additional thread_id attribute to privatemsg_new_thread and rename it to privatemsg_send or something like this. Then we have 2 possibilites:
1. Still let the user set subject and recipients. This means that someone using the api needs to know about privatemsg internals (how recipients are stored and so on), imho, because we don't want that, we are defining api functions at all... so I would say, this is a no-go.
2. Ignore those to parameter and load them, just like privatemsg_answer this currently does. However, an api call to answer an existing thread would then look like this (assuming the above): privatemsg_send(NULL, 'some text', NULL, NULL, $thread_id). This looks just ugly to me.I already mentioned webchick's blog post above, that's exactly what she was talking about:
The "...refactoring some_function() into several functions that each take parameters specific to their functionality... " is what I was trying to do...
However, the current patch is just hacked together and I'm sure that it can be improved. The validation part could be joined into one function, so that both functions would look like:
But, this is only my point of view...
Comment #11
litwol commentedI'm assuming the above validation example is part of privatemsg_send function. otherwise it doesnt make sense to trust developers to perform correct validation every time. imho.
Comment #12
berdirYes of course, this is part of the two top-level functions...
I updated them as written above, this time with patch, forgot it above...
I also created a test case for the API functions, but there isn't much there currently. And SimpleTest seems to be quite broken on d6...
Edit: As I was changing privatemsgapi.inc, I also fixed some Coding Style Issues and removed those group-functions as they are not used (anymore ?)
Comment #13
berdirSome updates...
- moved api functions to privatemsg.module, to reflect changes in #350344: Remove privatemsgapi.inc from module
- changed pm_send and pm_send_validate to use the api functions -> seems to work but not very well tested
No changes to te UnitTest, but it has to be saved in the tests directory to be recognised by SimpleTest.
Comment #14
berdirI started to work on #342733: Create upgrade path from privatemsg_attachments to filefield to see if the API works for such things. Several changes/improvements to make it work, in no partical order..
- Added #weight attribute to the buttons in privatemsg_new. This does make it possible to add things between the buttons and the textfields.
- Added a new attribute "#privatemsg_message" to the privatemsg_new form. This is similiar to #node in the node form and allows to save things like uploads in the cache while previewing/multiple upload.
- Added a privatemsg_message_delete hook, by loading the message before deleting it and calling the hook after the message has been marked as deleted. This needs still work, see below
- Some small changes in the validation logic
- hook privatemsg_message_insert called by module_invoke_all instead of drupal_alter.. no need to alter $message at this point
- Added privatemsg_message_load hook in _privatemsg_load. Does work like nodeapi load, return values are merged with $message
Open things...
Delete:
- There are two different levels of "delete"... 1 => User x deleted message y, he simply doesn't see it anymore. 2 => All users have deleted message y. Stuff like a attachments can now be deleted. With the current implementation, the hook privatemsg_message_delete does not distinguish between them, I am not sure if and how this should be done. Maybe an additional parameter $deleted_by_all. Other ideas?
This is the code I currently use in privatemsg_attachments to check this:
- There is still no delete api call, should we provide one and if yes, on thread and/or message level?
- Should we load the message for the delete hook, or let the sub modules load additional $message data if they need it: hook_privatemsg_message_delete($message) or hook_privatemsg_message_delete($pmid, $account)?
Show:
To show the attachments, my attachments module currently has a module_preprocess_privatemsg_view function, where it does extend $vars['message_body']. However, this does only work if privatemsg_preprocess_privatemsg_view does get called first. We may need a view/show hook to, one possibilty would be to replace the current privatemsg_pm_controls hook with something that can alter the whole $message, instead of just adding action links. Ideas ?
Caching/performance:
With multiple hooks, actions etc, a thread display can get quite heavy. Probably not in this issue (it's already big enough...), but we should think about caching and other things to improve performance...
Comment #15
berdirSome updates, I think it is pretty ready now...
Changes... (in the way the they occur in the v3-> v4 patch diff :) ):
- Added a 'privatemsg_message_view_alter'-hook in privatemsg_preprocess_privatemsg_view. This one does replace the action-specific "privatemsg_pm_controls"-hook. The hook has a single parameter "$vars". This is needed because the privatemsg preprozess function is the first that needs to be run. If we would explicitly set the weight of privatemsg and all related modules, we could get rid of it.
- Added a privatemsg_message_delete function. It gets called by privatemsg_delete_submit.
- Moved the delete_by_all check (see above) to privatemsg_message_delete and added a new parameter $deleted_by_all to hook_privatemsg_message_delete
- Removed the privatemsg_per_message_actions function, $vars['message_actions'] is a array now and submodules can add things with hook_privatemsg_message_view_alter. Moved the generation of the html to the template file
- Removed privatemsg_privatemsg_pm_control, moved to privatemsg_preprocess_view (It's just one line and with the above change we don't need to use a hook in privatemsg.module itself
- Updated privatemsg_get_link to check uid of recipient and author
- Updated privatemsg.author-pane.inc to use privatemsg_get_link
- Updated pm_block_user.module to use hook_privatemsg_view_alter instead of hook_privatemsg_pm_control. While doing this, I saw that the module currently makes 3 queries per message display. Thanks to the $vars parameter and a hook_privatemsg_load_alter I managed to switch 3 single queries against 1 LEFT JOIN.
Follow-Ups/TODO's:
-Document all the ways one can now extend and alter privatemsg. Probably as a page in the Drupal Documentation, I need to find time for that...
- Add API functions for thread load and deletion. Maybe as part of #348907: Per thread/Multiple thread actions or #328049: No headline shown when i send a message with user ID.
- Think about caching/performance: I did a short test and cached the $message array generated by privatemsg_load, but it wasn't really useful. I think, we should cache on thread level instead.
- Get testers and feedback :)
----
About the feedback part... I know, this issue is harder to understand and seems to be less important than others as it is not directly UI related. However, important features like email notification and attachments depend on this functionality. So It would be great if some people could install the patch and report if it works. I'll even attach all changed files so the only thing to do is unzip them. However, I don't recommend to do it on a live site :)
Hrm... the patch itself is bigger than the zipped version of all changed files :)
Comment #16
naheemsays commentedCan you attach the patch again please?
I have been on the sidelines for a while now but I need to jump back in. This should be as good a point as any other.
Comment #17
berdirWhat the f... I'm going crazy, I'm 100% sure that I attached the patch.
Comment #18
naheemsays commentedwith this patch, I cannot seem to view the message contents.
I can see the action buttons but nothing else - the actions do not have a pmid at the end either?
Comment #19
naheemsays commentedThat bug I mention above is when the block user messages module is enabled.
Comment #20
berdirOk, I'll look into it.
Comment #21
berdirHm, I have an idea why it does break on your site. Can you please execute the following execute the following sql statement?
UPDATE system SET weight =5 WHERE name = 'pm_block_user'Note: This is a temporary workaround. Instead of again hacking around this issue with array_unshift an similar tricks, I'd like to fix this via: #360021: Improvement to _privatemsg_assemble_query. Comments are welcome ;)
Comment #22
naheemsays commentedyup, that fixes it. as for the other issue, it does seem to make things simpler/nin-hackish so I do agree, but since I do not know too much about databases, I considered that an uninformed "me too"...
Comment #23
naheemsays commentedsince the bug was not here, setting back to cnr for now.
I am still uncomfortable for different functions for start a new conversation and to reply to one. I do not think those using the API should have to care either which way...
Comment #24
litwol commented@nbz: ping me in IRC when you get a moment.
Comment #25
berdirHm. Seems that I wasn't really successful in convincing you :)
My primary reason for splitting them up is still to make those functions easier to understand/use, see comment #7.
I wasn't able to come up with a function definitition that works for both use cases, so I splitted them up. I also thought if we really need an api function to answer threads, but it could be nice for a auto-responder/away-message system for example.
Another thing that's not really good are the function names. Maybe privatemsg_reply would be better as privatemsg_answer, now idea how to improve new_thread.
Comment #26
naheemsays commentedNo probs - that was just my concern.
Another thing - in privatemsg_answer, the participants are set, but the blocked users are not removed. This will just send notices of undelivered messages in cases where it may not really needed to do that.
As for button weights - should there be a numericla gap between them just in case other modules want to insert something in between?
line 42 od patch as available spelt wrong, but I never looked at such things past that.
Apart from that it looks good to me.
For my original problem above, do we need an update function or is the problem something else?
Comment #27
berdirHm, that part is a bit tricky, I haven't found a better solution yet. Currently, it works in the following way:
- I moved the privatemsg_block_message stuff to _privatemsg_validate_message, because we need to do this in answer, new_thread and the form validation.
- However the messages about blocked users should only be displayed when a users tries to send a message with the form. So I added a $show_warnings flag to _privatemsg_validate_message, so that the function only displays blocked user notices when it's set to true
- So, privatemsg_answer adds all recipients and maybe some of them are removed at a later point, but this shouldn't be a big performance hit, because we need to user_load them anyway.
Hm, good point. I doubt that anything like this will ever be done, but there is no downside of doing it so, i changed them to 10, 15 and 20 and also added #weight to the other fields.
If the mentioned issue about _privatemsg_assemble_query above gets in first, I can re-roll that patch and the update isn't needed anymore. Would imho be easier
Also fixed two small E_NOTICE bugs when previewing a message.
Comment #28
berdirre-roll of patch as there were some minor conflicts.
- privatemsg_get_link does now check the "read privatemsg" permission of the recipient
- some code style issues in the changed code
Comment #29
naheemsays commentedIt works and looks good to me (there is a small offset for one of the patch hunks though). I will set it to rtbc.
IMO there is a need to pass through from load to display wether the user has read that message before or not, but that would be a separate feature request which should not hold this patch up.
PS the RTBC is conditional that this should go in AFTER #360021: Improvement to _privatemsg_assemble_query.
Comment #30
berdirCare to explain this a bit more ? $message['is_new'] / $row['is_new'] is 1 if the user hasn't read the message, isn't that what you mean?
Note: The patch needs to be re-rolled after #360021: Improvement to _privatemsg_assemble_query goes in, as the function name of the sql hook does change.
PS: I started to document all those functions and hooks, still much to do but it is a start: http://drupal.org/node/369399
Comment #31
naheemsays commentedyup - it will need to be rerolled.
yup, but added into privatemsg_privatemsg_messages_alter/privatemsg_sql_messages and then passed into the theming layer so that for each individual message can have a "new" display/anchor when viewing the message. Actually this is totally different from this patch anyway.
Comment #32
naheemsays commentedJust re-rolling this atm.
Comment #33
berdirI've already done it, uploading soon...
Comment #34
berdirOk, rerolling patch as #360021: Improvement to _privatemsg_assemble_query has been commited (Hooray! :) )
Some minor changes:
- renamed sql hooks and assemble calls
- added first bits of apidoc, more will follow in an own patch later
- added $message['user'] = $account in privatemsg_load, so that hooks know which user is doing stuff with the message
Comment #35
naheemsays commentedyup, it works.
Comment #36
berdirForgot to add the updated test file. It doesn't have much tests, only some simple validation/permission tests. It should be added to the tests folder.
Comment #37
joe9 commentedHi, I'm using the "Flag Friend"-Module which has been developed by sirkitree and provides a very nice friendlist-function for D6. I think it would be very useful if the to modules "Privatemsg" and "Flag Friend" could be combined.
Unfortunately I'm no programmer so I don't know anything about the module coding but I assume that combining "Privatemsg" with other modules is what you are talking about here :) ?
I posted my request already in the "Flag Friend"-Project (http://drupal.org/node/372226) and sirktree replied he would review a possible patch.
Now my question is: Is it possible that any of you guys would have a closer look on this issue? That would be great!
(Please note: I'm quite new in the Drupal community so please forgive me, if this is a unusual way to post a request)
Thanks & regards!
Comment #38
litwol commentedremoved double post
Comment #39
litwol commented@joe9: Move feature request to new issue to avoid highjacking original issues ;)
Comment #40
berdirOk, hopefully the last update.
- Changed $uid parameter to $account in sql_load, sql_messages and _privatemsg_load()
- Use $account parameter instead of $fragments['query_args'][0] in privatemsg_filter_privatemsg_sql_list() - Don't ask me what I was thinking then.. :-/
- added apidoc for privatemsg_get_link
Comment #41
berdir@joe9
Feel free to use http://drupal.org/node/373044 as a start for integrating your module with Privatemsg. If there are any question, just ask and I'll try to improve the example.
Comment #42
andypostGet this to test...
Comment #43
naheemsays commentedI have tested this - it applies cleanly and seems to work well, but I will give it another once over tomorrow before marking rtbc (unless I am beaten to it by someone else).
Comment #44
litwol commentedextra tests never hurt :)
Comment #45
joe9 commented@litwol: o.k. :) I have already opened a feature request in the "Flag Friend" - Project (http://drupal.org/node/372226) and I won't handle this issue within this node anymore. My intention was to match the right people for this issue :)
Comment #46
joe9 commented@Berdir: I'm afraid I won't have any questions since I don't have a clue about this :) But as you have posted your comment also in the feature request for this (http://drupal.org/node/372226) there might be some other people coming up with questions. Thank you very much & best regards!
Comment #47
andypostWorks well but restriction for non-empty subject is not good, IMO if subject is empty it should filled with default - "no subject" for example in listing of new message
After IRC there's idea to leave this to another issue to reduce this patch
Comment #48
berdirTo explain this a bit more, the current version allows to make the subject and body field to be optional by using hook_form_alter. However, _privatemsg_message_validate doesn't allow that anymore.
The idea is to create a follow-up patch which adds a configuration option to make the subject optional and prefills it.. either with "no subject* or with substr($body, 0, 20).
However, if I keep adding features to that patch, it will never be commited :)
Comment #49
litwol commented1) removed
from privatemsg_get_link because we should allow sending messages to self ? i know we used this function in places such as user profile and we dont want to show link to send message to oneself, however i feel that this API should be pure and return what is asked of it, a link to message to recepient's account and since the core of the module allows sending messages to self thus i felt its important to let this function do the same.
if it still make sense to not show link to message oneself in places like user profile page, then we should implement checks there to prevent calling this function.
2)
in privatemsgapi.inc we have this code:
Notice the call : module_invoke_all('privatemsg_message_load', $message);
I scanned privatemsg code base and nowhere does it define hook_privatemsg_message_load. is this a deprecated or broken feature ?
Comment #50
litwol commentedgreat stuff ! This went in but now we need to fix the following critical bug:
critical bug: #376034: #288183 followup: user blocking doesnt work when sending to group of users that contains at least one non blocked user.
other patch review comments:
#376023: #288183 followup: change hook_privatemsg_block_message to work on multiple recipients
#376020: #288183 followup: possibility to allow empty subject on messages: in validate _privatemsg_validate_message
#376005: #288183 followup: _privatemsg_send always returns TRUE. change that to return more relevant information.
#375999: #288183 followup: Developer friendlify privatemsg_new_thread API.
#375980: #288183 followup: remove complex php logic from privatemsg-view.tpl.php
Thank you everyone!
Comment #51
berdir> 2) I scanned privatemsg code base and nowhere does it define hook_privatemsg_message_load. is this a deprecated or broken feature ?
It is a not yet used feature :) Some things can't be done with hook_privatemsg_sql_load_alter, because there can be multiple elements, for example, privatemsg_attachments does use it to check and load attachments,
Comment #52
cincy_kid commentedsubscribe
Comment #54
frankcarey commentedI'm trying to use the new api function in a migrate integrations module, so that people can load in privatemsg messages programatically from a view , file or database (even an external one). I updated to DEV to use it, but looking at the code, I see a possible flaw.
IF the custom options are added before the defaults, won't they get overridden? ( i want to set timestamp myself)
// set custom options, if any
Comment #55
berdirNo, actually not.
I know, it's confusing, but "adding" arrays doesn't overwrite existing values. See http://ch2.php.net/manual/en/language.operators.array.php
Comment #56
frankcarey commentedah, that's a handy bit of code. I can certainly use that in my development. sorry for my confusion :)
Comment #57
litwol commentedWhat is the reason to open this issue agian ?
Comment #58
frankcarey commentedsorry, didn't mean to reopen. I need to get the mid right after I send the message, how can i do that?
Comment #59
berdirAsking questions in closed threads isn't a good idea neither, please open new issues for questions.
Currently, the only way to do that is either with "db_last_insert_id('pm_message', 'mid')" or with http://blog.worldempire.ch/de/api/function/hook_privatemsg_message_insert/1, the $message array will contain the mid at that point. But then you'd have a problem accessing your other data.
However, I think it makes sense to either return $message or $mid in _privatemsg_send() and the two functions that use it. Currently, the function only returns TRUE. We should continue that in #376005: #288183 followup: _privatemsg_send always returns TRUE. change that to return more relevant information..