Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

osTicket v1.10 (stable) and Maintenance Release v1.9.15 are now available! Go get it now

[MOD] Staff Reply to Tickets (IMAP)

245

Comments

  • southside;39598 said:
    Jemson;

    Thanks for the mod which seems to work but we are now getting the following error emailed from our cron task:

    Subject:

    /usr/bin/php /var/www/vhosts/domain.com/httpdocs/support/api/cron.php

    Body:

    PHP Warning: preg_match() expects parameter 2 to be string, object given in /var/www/vhosts/domain.com/httpdocs/support/include/mysql.php on line 188 PHP Warning: mysql_real_escape_string() expects parameter 1 to be string, object given in /var/www/vhosts/domain.com/httpdocs/support/include/mysql.php on line 179

    Can you help?
    I had looked at something like this once before, I was not getting emailed alerts to this effect, but had seen it in the logs or when invoking the cron command from CLI.
    I will have to check it out to see if its the same issue.
    From memory it wasn't from the mod specifically but I will investigate further for you.
  • Southside,

    I have had a look at this and the offending component is the db_input function.
    Looks like when one of the variables is not being passed correctly to the function. Can you confirm you are running 1.7ST and also how you implemented the mod? Ie. From zip or if you manually made the alterations.
    I'm thinking it's either a typo on one of the variables in the mod or you may be running an RC version of 1.7 as I know several of the variable names changed between 1.7RC5 and 1.7ST.
  • 1.7ST I think

    Jemson;

    Not sure We downloaded the 1.7 version on 2nd April 2013.

    In looking at the original ZIP I think it is the stable release.

    I have attached the whats new from the file will that help you determine version?

    PS also I used the original files from the ReplyPatchv3.zip and patched in a few lines of code for a new field called "Country" into the:

    class.mailfetch.php
    class.ticket.php

    This should not affect your changes as far as I see but maybe, I have attached the two altered files for your reference.


    SC
    MY EDITED FILES.zip
    24K
  • Perfect

    This worked perfectly.
  • Southside,

    I have compared the files and as you suspected the only difference is the country field mod so looks like you are running the stable release.

    From a quick look at what you have in relation to the country field mod I would expect that error could be generated if the country ID is null.

    In an emailed reply scenario I imagine the country would be pushed through as null as there is nowhere to set it and it will generate the reported errors.
    To avoid this you may need to employ something into my mod such as;

    if(is_null($countryId))
    $countryId = 'None';


    The above should resolve the issue as it will actually send a variable through to the db_input(). I hope that assists in correcting your issue.
  • Where should the code go

    Jemson;

    Can you advise where the code should be inserted and in what file.

    So I can test your theory.

    Many Thanks.

    SC
  • southside;39901 said:
    Jemson;

    Can you advise where the code should be inserted and in what file.

    So I can test your theory.

    Many Thanks.

    SC
    Try putting it just below the global line in function postReply() in class.ticket.php
    Eg:

    function postReply($vars, &$errors, $alert = true) {
    global $thisstaff, $cfg;

    if(is_null($countryId))
    $countryId = 'None';

  • V3 is working beautifully so far in testing (hopefully the same holds true when we push it live...)

    I have a theoretical question: The code you added for closing a ticket from the subject line is a huge win for us, it's functionality we've been trying to figure out for a while.

    What are the chances it could be adapted for assigning a ticket? Something like adding

    "#assign;tech1"

    into the subject line? It's not the most elegant solution but would get the job done for the time being.

    Thank's for the awesome work, you made my whole week with this.
  • Jemson;39603 said:
    Are you running the stable release or one of the RCs?
    The first mod instance was written on RC4 and caused a similar issue on ST. It was then rewritten for ST, so im thinking its possible you are running an RC version and having the same issue?
    We are running version 1.7.0 Released April 02, 2013. Just so that you don't need to scroll to my previous thread, here is the issue.
    alltime;39596 said:
    For some reason, my instance (1.7.0) just keeps creating new tickets with the files from ReplyPatchv3.zip.

    Do the templates have to have a specific format for the script to recognize it should close or reply? This is an example of a reply as a staff member:



    What gives?
    I appreciate your continued support for this.
  • @thebullfrog
    Have been working on this, hoping to upload a v4 in the next couple of hours that has this functionality.

    @alltime
    Do you have any other mods? The only other user that has reported an issue in Patch v3 on 1.7 ST was due to another mod.
    What is the subject on the email that the admin user is replying to?
  • Version 4

    As with previous versions please see below diff between v4 modded files and originals.
    Also attached is a zip containing the modded files.

    include/class.mailfetch.php

    diff class.mailfetch.orig class.mailfetch.php
    400c400
    < if(!($ticket=Ticket::lookupByExtId($tid, $vars['email'])))
    ---
    > if(!($ticket=Ticket::lookupByExtId($tid)))
    406,408c406,423
    < if(!($message=$ticket->postMessage($vars, 'Email')))
    < return false;
    <
    ---
    > $staffsql = 'SELECT staff_id, firstname, lastname, email FROM '.STAFF_TABLE.' WHERE email='.db_input($vars['email']).' LIMIT 1';
    > $vars['poster'] = $vars['name'];
    > if(($staffres=db_query($staffsql)) && (db_num_rows($staffres) == 0)){
    > if(!($message=$ticket->postMessage($vars, 'Email')))
    > return false;
    > } else {
    > $staffvars=db_fetch_row(db_query($staffsql));
    > $replyvars=Array(
    > \"msgId\" => $ticket,
    > \"response\" => $vars['message'],
    > \"poster\" => $staffvars['1'].' '.$staffvars['2'],
    > \"staffId\" => $staffvars['0'],
    > \"subject\" => $vars['subject'],
    > );
    > $errors=array();
    > if(!($msgid=$ticket->postReply($replyvars, $errors)))
    > return false;
    > }


    include/class.ticket.php

    diff class.ticket.orig class.ticket.php
    1314a1315,1317
    > if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
    > $msg['body'] =\"\n$tag\n\n\".$msg['body'];
    >
    1402a1406,1411
    >
    > //Strip quoted reply...on emailed replies
    > if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($vars['response'], $tag))
    > if(list($msg) = split($tag, $vars['response']))
    > $vars['response'] = $msg;
    >
    1442a1452,1495
    > }
    >
    > //Check for actions in the subject
    > if($vars['subject']){
    > $errors=array();
    > $intvars = array(
    > \"title\" => \"Emailed Action\",
    > \"note\" => \"\",
    > );
    > }
    >
    > if($vars['subject'] && preg_match (\"/#claim/\", $vars['subject'], $action)) {
    > $this->setStaffId($vars['staffId']);
    > $intvars['note'] = \"Ticket has been claimed via email.\";
    > $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    > }
    >
    > if($vars['subject'] && preg_match (\"/#assign:/\", $vars['subject'], $action)) {
    > $match = preg_split(\"/#assign:/\", $vars['subject']);
    > $assignee = preg_split(\"/ /\", $match['1']);
    > $chksql = 'SELECT staff_id FROM '.STAFF_TABLE.' WHERE username='.db_input($assignee['0']).' LIMIT 1';
    > if($astaff_id = db_result(db_query($chksql))){
    > $this->setStaffId($astaff_id);
    > $intvars['note'] = \"Ticket has been assigned to {$assignee['0']} via email.\";
    > $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    > }
    > }
    >
    > if($vars['subject'] && preg_match (\"/#unassign/\", $vars['subject'], $action)) {
    > $this->setStaffId('0');
    > $intvars['note'] = \"Ticket has been unassigned via email.\";
    > $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    > }
    >
    > if($vars['subject'] && preg_match (\"/#reopen/\", $vars['subject'], $action)) {
    > if($this->isClosed()) $this->reopen();
    > $intvars['note'] = \"Ticket has been reopened via email.\";
    > $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    > }
    >
    > if($vars['subject'] && preg_match (\"/#close/\", $vars['subject'], $action)) {
    > $this->close();
    > $intvars['note'] = \"Ticket has been closed via email.\";
    > $this->postNote($intvars, $errors, $vars['poster'], $alert='true');


    I've also included a README in this release to assist in operation and actions, this is inside the patch zip, but also included separately for those not in need of the modded files.
    ReplyPatchv4.zip
    23K
    README.txt
    2K
  • This is great...Thanks again!

    Does this include the Claim Ticket by reply as well?
  • adidasrta;40110 said:
    This is great...Thanks again!

    Does this include the Claim Ticket by reply as well?
    Yes. Claim on reply can be achieved with #claim in the subject.
    Also includes #assign #unassign #close #reopen (these are listed/detailed in the readme).

    For the automatic claim on reply you were using, you will need to stick to that function that was added in the other thread.
  • ok cool...

    yeah i was talking about the auto claim. I'll re-add it, but will it conflict since it has the conflict as a subject line?
  • Won't be any conflict.

    You would have access to both methods whereby an unclaimed ticket would automatically be claimed (from your other mod) and you would still have the ability to #claim in the subject line and reassign someone else's ticket to yourself (from this mod).
  • Brilliant mod, thank you for taking the time to make it, it's the only thing I thought osTickets was missing.

    Only one suggestion and that is would it be possible for it to check the message body instead of the subject for the #close, etc. as I personally find it counter-intuitive after having spent a lot of time with Spiceworks.
  • @Jemson, all seems to be working perfectly with the installation of ReplyPatchv4.zip. Thank you very much!

    @Pawned, I think that this is an excellent suggestion also. Especially with techs who work in the field, editing the body is much easier than the subject. Although, I am just grateful that we now have this feature!
  • We actually did get a system working for assigning through Email ourselves, just never got a chance to update this. When I get time Ill have to compare our implementations of it.

    Do have a concern though: ever since V3 (before we added our assignment functionality) after a while we get an message that there have been to many errors and we have to manually check our mailbox, but there are no further details and we haven't been able to work out WTF it's even complaining about. I'd love to include the logfiles from the server, but I dont have access to those despite being the person assigned to making this work, go figure :rolleyes: We initially thought it was an autocron/Gmail issue on our test build, but after pushing V3 live we're getting it on the live server which was set-up manually the "right" way through an exchange server.

    EDIT: Your implementation is vastly different than ours, but that's more because the boss wants to do this from his iphone and is too lazy to remember/type full user names lol. We set it up so he only needs the first couple letters of the users first name, or the team. When I get a chance I put up how we did it.

    As far the error goes we cant replicate it so far, it seems to be random, but we do know it's occuring in mailfetch.php somewhere.
  • Ahha! Nevermind the error WAS something we did, so all is well there.
  • hi Jemson,
    Your mod is great, could you upgrade to process attachment in next release.
    Update: when user or staff reply with attach, file couldn't upload to system
  • thebullfrog;40333 said:
    We set it up so he only needs the first couple letters of the users first name, or the team. When I get a chance I put up how we did it.
    Would it be possible for you to send me this? It'd be great to have as our usernames are quite long and can become pretty tedious to type out the full name.

    Edit: Also, Jemson, would it be possible to get this to not email the customer that staff has replied when there is a command in the email?

    Not sure if it does that already, I have tweaked the code myself so that it checks the body for the commands instead of the subject, and the customer gets an email saying a staff member has replied saying #claim xD

    Edit2: Or perhaps just a #internal command or something, which then just turns the email into an internal note and thus doesn't email the customer? I think this would actually be a more elegant solution than what I said above as it allows the staff member to decide whether or not the customer needs to see the message.
  • Maybe if the command is in the subject, it is a reply to the end user.

    If the command is in the body, it is internal?
  • Hi Guys,

    Loving the feedback.

    I will have some spare time tonight so I will add the #internal option as well as the attachments ability. Both are really good points.

    I can configure it so if #internal is set it will avoid sending the requester an email at all. Typically in my scenario I wouldn't be doing a straight #option only, I would be claiming in the subject but then be putting something like "I will look into this and get back to you later today" or #close "Please let me know if you need any further assistance" etc in the body for the customer update.

    Changing from subject #options to body in v4 would be as easy as just changing a couple of variables in your patch install. I opted for subject as these are not sent to the customer at all as opposed to the customer seeing #claim etc in the body. I love the #internal idea though and am thinking I can have it check both subject and body for the #options which should give the best of both worlds and send no emails to the requester if #internal is set.

    Will give it some thought and run some test scenarios over the next couple of hours and let you know what I come up with.
  • Awesome, I look forward to the next update.

    Thanks for your work, Jemson!
  • Reply Patch 4.1

    Have added an incremental update to Patch 4 as mentioned above based on requests.

    - Staff can now email attachments that will be added to the ticket
    - #actions can be included in either the subject, body, or a combination of the two in one email
    - Added #internal as an action that marks the reply and in internal note and is not sent to the requester.

    Presently emailed attachments are not forwarded via email to either staff or the requester. I don't see much of a need for staff need to get an email with attachments sent from the requester (will just clog up mail servers), BUT I think it would be useful for the requester to receive any attachments forwarded from staff. Have looked into this but the structure of the existing functions will make this very difficult. Something for another day.

    As always, any bugs or suggestions please let me know.

    Have attached zip and README, and also have diffs listed below.

    include/class.mailfetch.php

    diff class.mailfetch.php class.mailfetch.orig
    400c400
    < if(!($ticket=Ticket::lookupByExtId($tid)))
    ---
    > if(!($ticket=Ticket::lookupByExtId($tid, $vars['email'])))
    406,423c406,408
    < $staffsql = 'SELECT staff_id, firstname, lastname, email FROM '.STAFF_TABLE.' WHERE email='.db_input($vars['email']).' LIMIT 1';
    < $vars['poster'] = $vars['name'];
    < if(($staffres=db_query($staffsql)) && (db_num_rows($staffres) == 0)){
    < if(!($message=$ticket->postMessage($vars, 'Email')))
    < return false;
    < } else {
    < $staffvars=db_fetch_row(db_query($staffsql));
    < $replyvars=Array(
    < \"msgId\" => $ticket,
    < \"response\" => $vars['message'],
    < \"poster\" => $staffvars['1'].' '.$staffvars['2'],
    < \"staffId\" => $staffvars['0'],
    < \"subject\" => $vars['subject'],
    < );
    < $errors=array();
    < if(!($message=$ticket->postReply($replyvars, $errors)))
    < return false;
    < }
    ---
    > if(!($message=$ticket->postMessage($vars, 'Email')))
    > return false;
    >


    include/class.ticket.php

    diff class.ticket.php class.ticket.orig
    1315,1317d1314
    < if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
    < $msg['body'] =\"\n$tag\n\n\".$msg['body'];
    <
    1406,1421c1403,1404
    <
    < //Strip quoted reply...on emailed replies
    < if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($vars['response'], $tag))
    < if(list($msg) = split($tag, $vars['response']))
    < $vars['response'] = $msg;
    <
    < //Check if tagged as internal and post as a note instead.
    < if(($vars['subject'] && preg_match (\"/#internal/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#internal/\", $vars['response'], $action))) {
    < $vars['note'] = $vars['response'];
    < if(!($response=$this->getThread()->addNote($vars, $errors)))
    < return null;
    <
    < } else {
    < if(!($response = $this->getThread()->addResponse($vars, $errors)))
    < return null;
    < }
    ---
    > if(!($response = $this->getThread()->addResponse($vars, $errors)))
    > return null;
    1459,1516c1442
    < if(($vars['subject'] && preg_match (\"/#internal/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#internal/\", $vars['response'], $action))) {
    < //Do not email requester if marked #internal
    < } else {
    < $email->send($this->getEmail(), $msg['subj'], $msg['body'], $attachments);
    < }
    <
    < }
    <
    < //Check for actions in the subject
    < if($vars['subject']){
    < $errors=array();
    < $intvars = array(
    < \"title\" => \"Emailed Action\",
    < \"note\" => \"\",
    < );
    < }
    <
    < if(($vars['subject'] && preg_match (\"/#claim/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#claim/\", $vars['response'], $action))){
    < $this->setStaffId($vars['staffId']);
    < $intvars['note'] = \"Ticket has been claimed via email.\";
    < $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    < }
    <
    < //Check for ticket assignment in subject
    < if($vars['subject'] && preg_match (\"/#assign:/\", $vars['subject'], $action)){
    < $match = preg_split(\"/#assign:/\", $vars['subject']);
    < }
    < //Check for ticket assignment in subject
    < if($vars['response'] && preg_match (\"/#assign:/\", $vars['response'], $action)) {
    < $match = preg_split(\"/#assign:/\", $vars['response']);
    < }
    < //Assign the ticket if a match is found above
    < if(isset($match)){
    < $assignee = preg_split(\"/ |\r|\n|\r\n/\", $match['1']);
    < $chksql = 'SELECT staff_id FROM '.STAFF_TABLE.' WHERE username='.db_input($assignee['0']).' LIMIT 1';
    < if($astaff_id = db_result(db_query($chksql))){
    < $this->setStaffId($astaff_id);
    < $intvars['note'] = \"Ticket has been assigned to {$assignee['0']} via email.\";
    < $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    < }
    < }
    <
    < if(($vars['subject'] && preg_match (\"/#unassign/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#unassign/\", $vars['response'], $action))) {
    < $this->setStaffId('0');
    < $intvars['note'] = \"Ticket has been unassigned via email.\";
    < $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    < }
    <
    < if(($vars['subject'] && preg_match (\"/#reopen/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#reopen/\", $vars['response'], $action))){
    < if($this->isClosed()) $this->reopen();
    < $intvars['note'] = \"Ticket has been reopened via email.\";
    < $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    < }
    <
    < if(($vars['subject'] && preg_match (\"/#close/\", $vars['subject'], $action)) OR ($vars['response'] && preg_match (\"/#close/\", $vars['response'], $action))){
    < $this->close();
    < $intvars['note'] = \"Ticket has been closed via email.\";
    < $this->postNote($intvars, $errors, $vars['poster'], $alert='true');
    ---
    > $email->send($this->getEmail(), $msg['subj'], $msg['body'], $attachments);
    README.txt
    2K
    ReplyPatch4.1.zip
    23K
  • Brilliant, thanks a lot for the update :D
  • Awesome!

    On that same note, I don't know if it is possible to have an 'ELSE' statement for other people responding to the ticket outside of staff.

    We have situations where 3-4 people, including the email to OSticket is sent to.

    The problem is that it generates a new ticket for everyone involved. I'm not sure if this would help here, or if a CC mod was more appropriate.
  • adidasrta;40464 said:
    Awesome!

    On that same note, I don't know if it is possible to have an 'ELSE' statement for other people responding to the ticket outside of staff.

    We have situations where 3-4 people, including the email to OSticket is sent to.

    The problem is that it generates a new ticket for everyone involved. I'm not sure if this would help here, or if a CC mod was more appropriate.
    I have just tested this and it is still working in the latest patch.
    Scenario was: I created a ticket, got a response and CC'ed someone on my email reply. The CC'ed user then replied to this email and the response was added to the ticket.

    The only scenario this doesn't work in is if a person is CC'ed on the original request ticket and replies to that, which WILL generate a new ticket as there is no ticket number in the subject to match it to.

    With a CC mod the system would potentially email a ticket creation response to all users which they would hopefully reply to rather than the request email.
    CC integration is still on my todo list, but will be quite complex to implement as there are a lot of considerations for different scenarios, how to deal with requests to be removed from the CC list etc.
  • Would it be possible for email commands to be recognised in initial ticket creation emails?

    A lot of the time we will create tickets ourselves via email after we've received a phone call or have something to do in the office, so it would be pretty handy if it could detect we are staff and allow us to do #claim, #close (if the incident was resolved instantly over the phone), etc. in the initial email.
  • Not seeing a difference...

    Hello,

    I'm using 1.7.0 Stable and have a fully functioning set-up on a hosted Apache environment.

    After reading this post, I was very excited about this MOD.

    I uploaded the two files and carefully read the README file. If I was supposed to do something with the database, I didn't see the instruction for that.

    The result? When I reply to an open ticket with #close it just adds that to the ticket thread. I also tried assign: and that didn't work for me either.

    Too many people are high-fiving this mod, so I have to believe it's my problem. Any thoughts?

    Other details:
    - Responsive Template by JayPick
    - POP in / SMTP out / Cron set-up
    - Readme.txt compliant settings
    - Ticket management, Email Templates, Actions - all working

    Thank you,

    Webb
Sign In or Register to comment.