I would like to iterate through this list of users and in place "variable" below, run the function three times, each time replacing variable with bob, fred, and then nancy.
import boto3
client = boto3.client('iam')
users = ['bob', 'fred', 'nancy']
for user in users:
client.create_user(
UserName='variable'
)
Figured it out:
import boto3
client = boto3.client('iam')
users = ['bob', 'fred', 'nancy']
for user in users:
client.create_user(
UserName = (user)
)
Related
we store a GitHub account in one of the AD User attribute. When receiving a Pull Request webhook from GitHub I want to find a user based on GitHub Account and notify user about tests results. How to do that?
if I understand you correctly you want to take email attribute value by another user attribute. can't test the following code but it should give you an idea how to do that.
import javax.naming.directory.InitialDirContext
import javax.naming.directory.DirContext
Properties ldapProps = [
'java.naming.factory.initial' :'com.sun.jndi.ldap.LdapCtxFactory',
'java.naming.security.authentication':'simple',
'java.naming.provider.url' :'ldap://ldap-host:389',
'java.naming.security.principal' :'ldap-access-username',
'java.naming.security.credentials' :'ldap-access-password',
] as Properties
String user = 'user-to-search'
String attr = 'mail' //attribute name for email could be different in your ldap
String ldapFilter = "CN=${user}" //put instead of `CN` git attribute
String[] attrValues = [] //array because could be several values for one attribute
DirContext ldapCtx = new InitialDirContext(ldapProps)
ldapCtx.search("", ldapFilter, null).each{ldapUser->
def ldapAttr = ldapUser.getAttributes().get(attr)
attrValues = ldapAttr?.getAll()?.collect{it.toString()}
}
ldapCtx.close()
println "found values: $attrValues"
I'm helping an organization out and they wish to have a website in which you input some numbers and a Google Sheets link should appear in which the numbers are put into some formula to give a result (i.e if you put in 5, 5, 3; (Num1 + Num2) * num3 it'd show a table in which the first two numbers are added then multiplied by the third:
Num1 Num2 Num2 Result
5 5 3 30
I have searched GitHub and the internet but I cannot seem to find a library that can create a Google Sheet from a website with given data input into a formula. Most stuff I found used the gsheet API and only modified an existing sheet. I found a Python (Flask) library called xlsxwriter and I was wondering if there is any way to convert an .xlsx to an online Google Sheet or if possible to just make a Google Sheet from my website.
(My website is in Flask as of right now but since I literally have no backend. If someone knows of a library that is in another web framework, I am willing to switch.)
Thank you, John D
Maybe I am missing something here but the regular Google Sheets API (which is available for Python) allows you to create blank spreadsheets with a specified title.
spreadsheet = {
'properties': {
'title': title
}
}
spreadsheet = service.spreadsheets().create(body=spreadsheet,
fields='spreadsheetId').execute()
print('Spreadsheet ID: {0}'.format(spreadsheet.get('spreadsheetId')))
https://developers.google.com/sheets/api/guides/create
https://github.com/gsuitedevs/python-samples/blob/master/sheets/snippets/spreadsheet_snippets.py
https://developers.google.com/sheets/api/quickstart/python
Here is a more complete sample based on the Google Quickstarts examples:
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle! Adjust scopes as needed
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
def main():
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('sheets', 'v4', credentials=creds)
# Call the Sheets API
spreadsheet = {
'properties': {
'title': 'New Test Sheet 2'
}
}
spreadsheet = service.spreadsheets().create(body=spreadsheet,
fields='spreadsheetId').execute()
#print('Spreadsheet ID: {0}'.format(spreadsheet.get('spreadsheetId')))
spreadsheet_id = spreadsheet.get('spreadsheetId')
range_name = 'Sheet1!A1:D5'
body = {
"majorDimension": "ROWS",
"values": [
["Item", "Cost", "Stocked", "Ship Date"],
["Wheel", "$20.50", "4", "3/1/2016"], # new row
["Door", "$15", "2", "3/15/2016"],
["Engine", "$100", "1", "30/20/2016"],
["Totals", "=SUM(B2:B4)", "=SUM(C2:C4)", "=MAX(D2:D4)"]
],
}
result = service.spreadsheets().values().update(
spreadsheetId=spreadsheet_id,
range=range_name,
body=body,
valueInputOption='USER_ENTERED'
).execute()
print(result)
if __name__ == '__main__':
main()
I've looked at the Bitbucket API docs and this post BitBucket get list of all contributors. The second link asks about users belonging to a repo, but in my case I just want a list of ALL licensed users. Is there really NO way to do this or did I miss it in the docs?
Execute something like this:
curl -s --user USER:PASS --request GET https://BITBUCKET-SERVER/rest/api/1.0/admin/users?limit=1000 | jq --raw-output '.values[] | .name + " => " + .displayName'
And you'll get the "username => name" list of users.
Just for anyone else looking for this: The currently accepted answer provides a way to list all users, but this will include unlicensed users, i.e. user records that are not currently consuming a seat.
If you want to get a list of all licensed users, follow the steps described in How do I find which users count against my Bitbucket Server license? to install an add-on which will give you exactly this.
Here is some python code that did the trick for me. I had many users (10k+) but <1000 users with permissions. I also have basic authentication (username/passoword) enabled for my bitbucket server. By querying both "users" and "permissions" and merging the results using pandas, I got a pretty good result.
import pandas as pd
import numpy as np
import json
import requests
import datetime
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
bitbucket_url = "https://my-bitbucket-server"
users_url = bitbucket_url + "/rest/api/1.0/admin/users?limit=1000&start="
permissions_url = bitbucket_url + "/rest/api/1.0/admin/permissions/users?limit=1000&start="
out_filename = r"C:\mypath\authenticatedUsers.csv"
username = "myusername"
password = "mypassword"
def get_responses(url,username,password):
json_responses = []
with requests.Session() as s:
s.auth = (username,password)
start = 0
while(True):
response = s.get(url + str(start),verify=False)
json_response = json.loads(response.text)
if "values" not in json_response:
print("Error:" + response.text)
json_responses += json_response["values"]
if(len(json_response["values"]) < 1000):
break
start += 1000
return json_responses
users = pd.DataFrame(get_responses(users_url,username=username,password=password))
users["DaysSinceAuth"] = np.floor((datetime.datetime.now().timestamp() - users.lastAuthenticationTimestamp/1000)/3600/24)
permissions = get_responses(permissions_url,username=username,password=password)
permissions = pd.DataFrame([{"id":p["user"]["id"],"permission":p["permission"]} for p in permissions])
usersmerged = users.merge(permissions,how="inner",on="id")
usersmerged.to_csv(out_filename)
In my main page I have a list of users and i'd like to choose and open a channel to chat with one of them.
I am thinking if use the id is the best way and control an access of a channel like USERID1-USERID2.
But of course, user 2 can open the same channel too, so I'd like to find something more easy to control.
Please, if you want to help me, give me an example in javascript using a firebase url/array.
Thank you!
A common way to handle such 1:1 chat rooms is to generate the room URL based on the user ids. As you already mention, a problem with this is that either user can initiate the chat and in both cases they should end up in the same room.
You can solve this by ordering the user ids lexicographically in the compound key. For example with user names, instead of ids:
var user1 = "Frank"; // UID of user 1
var user2 = "Eusthace"; // UID of user 2
var roomName = 'chat_'+(user1<user2 ? user1+'_'+user2 : user2+'_'+user1);
console.log(user1+', '+user2+' => '+ roomName);
user1 = "Eusthace";
user2 = "Frank";
var roomName = 'chat_'+(user1<user2 ? user1+'_'+user2 : user2+'_'+user1);
console.log(user1+', '+user2+' => '+ roomName);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
A common follow-up questions seems to be how to show a list of chat rooms for the current user. The above code does not address that. As is common in NoSQL databases, you need to augment your data model to allow this use-case. If you want to show a list of chat rooms for the current user, you should model your data to allow that. The easiest way to do this is to add a list of chat rooms for each user to the data model:
"userChatrooms" : {
"Frank" : {
"Eusthace_Frank": true
},
"Eusthace" : {
"Eusthace_Frank": true
}
}
If you're worried about the length of the keys, you can consider using a hash codes of the combined UIDs instead of the full UIDs.
This last JSON structure above then also helps to secure access to the room, as you can write your security rules to only allow users access for whom the room is listed under their userChatrooms node:
{
"rules": {
"chatrooms": {
"$chatroomid": {
".read": "
root.child('userChatrooms').child(auth.uid).child(chatroomid).exists()
"
}
}
}
}
In a typical database schema each Channel / ChatGroup has its own node with unique $key (created by Firebase). It shouldn't matter which user opened the channel first but once the node (& corresponding $key) is created, you can just use that as channel id.
Hashing / MD5 strategy of course is other way to do it but then you also have to store that "route" info as well as $key on the same node - which is duplication IMO (unless Im missing something).
We decided on hashing users uid's, which means you can look up any existing conversation,if you know the other persons uid.
Each conversation also stores a list of the uids for their security rules, so even if you can guess the hash, you are protected.
Hashing with js-sha256 module worked for me with directions of Frank van Puffelen and Eduard.
import SHA256 from 'crypto-js/sha256'
let agentId = 312
let userId = 567
let chatHash = SHA256('agent:' + agentId + '_user:' + userId)
We are thinking of using Jira for bug tracking and to integrate it with Git to connect bug fixes with version handling.
Do you recommend Jira also for customer support or should we find another system like for example Zendesk for that purpose? I know that it is possible somehow to integrate for example Hipchat with Jira to enable chat functionality with customers but is Jira too complex for Customer Service to handle? What is your experience?
We use Jira for customer support, but we found that Jira is missing many must-have features that are needed for this. that's why we make many changes.
All and all, we are very happy with our choice, and we managed to save a lot of money by using Jira instead of other solutions.
Here are the major changes that we made, this will show you what is missing, while on the other hand show you that with a little bit of programming, Jira can do anything :)
Note: The scripts writen below should be attach to a workflow transition. The scripts are written using Jython, so it needs to be installed to use it.
Create issues by email
Jira only sends emails to Jira users. Since we didn't want to create a user for every person that addressed the support, we used anonymous users instead, and used scripts to send them email.
First, set Jira to create issues from emails. Than, use Script Runner pluging to save customer's email and names to custom field. . code:
from com.atlassian.jira import ComponentManager
import re
cfm = ComponentManager.getInstance().getCustomFieldManager()
# read issue description
description = issue.getDescription()
if (description is not None) and ('Created via e-mail received from' in description):
# extract email and name:
if ('<' in description) and ('>' in description):
# pattern [Created via e-mail received from: name <email#company.com>]
# split it to a list
description_list = re.split('<|>|:',description)
list_length = len(description_list)
for index in range(list_length-1, -1, -1):
if '#' in description_list[index]:
customer_email = description_list[index]
customer_name = description_list[index - 1]
break
else:
# pattern [Created via e-mail received from: email#company.com]
customer_name = "Sir or Madam"
# split it to a list
description_list = re.split(': |]',description)
list_length = len(description_list)
for index in range(list_length-1, -1, -1):
if '#' in description_list[index]:
customer_email = description_list[index]
break
# if the name isn't in the right form, switch it's places:
if (customer_name[0] == '"') and (customer_name[-1] == '"') and (',' in customer_name):
customer_name = customer_name[1:-1]
i = customer_name.index(',')
customer_name = customer_name[i+2:]+" "+customer_name[:i]
# insert data to issue fields
issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10401"),customer_email)
issue.setCustomFieldValue(cfm.getCustomFieldObject("customfield_10108"),customer_name)
Send customer issue created notification
Send the mail using the following script:
import smtplib,email
from smtplib import SMTP
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
import re
from com.atlassian.jira import ComponentManager
customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
cfm = ComponentManager.getInstance().getCustomFieldManager()
# read needed fields from the issue
key = issue.getKey()
#status = issue.getStatusObject().name
summary = issue.getSummary()
project = issue.getProjectObject().name
# read customer email address
toAddr = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10401"))
# send mail only if a valid email was entered
if (toAddr is not None) and (re.match('[A-Za-z0-9._%+-]+#(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}',toAddr)):
# read customer name
customerName = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10108"))
# read template from the disk
template_file = 'new_case.template'
f = open(template_file, 'r')
htmlBody = ""
for line in f:
line = line.replace('$$CUSTOMER_NAME',customerName)
line = line.replace('$$KEY',key)
line = line.replace('$$PROJECT',project)
line = line.replace('$$SUMMARY',summary)
htmlBody += line + '<BR>'
smtpserver = 'smtpserver.com'
to = [toAddr]
fromAddr = 'jira#email.com'
subject = "["+key+"] Thank You for Contacting Support team"
mail_user = 'jira#email.com'
mail_password = 'password'
# create html email
html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
html +='<body style="font-size:12px;font-family:Verdana">'
html +='<p align="center"><img src="http://path/to/company_logo.jpg" alt="logo"></p> '
html +='<p>'+htmlBody+'</p>'
html +='</body></html>'
emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
emailMsg['Subject'] = subject
emailMsg['From'] = fromAddr
emailMsg['To'] = ', '.join(to)
emailMsg.attach(email.mime.text.MIMEText(html,'html'))
# Send the email
s = SMTP(smtpserver) # ip or domain name of smtp server
s.login(mail_user, mail_password)
s.sendmail(fromAddr, [to], emailMsg.as_string())
s.quit()
# add sent mail to comments
cm = ComponentManager.getInstance().getCommentManager()
email_body = htmlBody.replace('<BR>','\n')
cm.create(issue,'anonymous','Email was sent to the customer ; Subject: '+subject+'\n'+email_body,False)
content of new_case.template:
Dear $$CUSTOMER_NAME,
Thank you for contacting support team.
We will address your case as soon as possible and respond with a solution very quickly.
Issue key $$KEY has been created as a reference for future correspondence.
If you need urgent support please refer to our Frequently Asked Questions page at http://www.example.com/faq.
Thank you,
Support Team
Issue key: $$KEY
Issue subject: $$PROJECT
Issue summary: $$SUMMARY
Issue reminder - open for 24/36/48 hours notifications
Created a custom field called "Open since" - a 'Date Time' field to hold the time the issue has been opened.
Created a custom field called "Notification" - a read only text field.
Using the Script Runner pluging , I've created a post-function and placed it on every transition going to the 'Open' status. This is to keep the issue opening time.
the code:
from com.atlassian.jira import ComponentManager
from datetime import datetime
opend_since_field = "customfield_10001"
# get opened since custom field:
cfm = ComponentManager.getInstance().getCustomFieldManager()
# get current time
currentTime = datetime.today()
# save current time
issue.setCustomFieldValue(cfm.getCustomFieldObject(opend_since_field),currentTime)
I've created a new filter to get the list of issues that are open for over 24h:
JQL:
project = XXX AND status= Open ORDER BY updated ASC, key DESC
Lastly - I've used the Jira remote API - the XML-RPC method to write a python script scheduled to run every 5 minutes. The script
reads all the issued from the filter, pulls all of them that have an 'Open' status for over 24h/36h/48h, send a reminder email, and mark them as notified, so only one reminder of each type will be sent.
The python code:
#!/usr/bin/python
# Refer to the XML-RPC Javadoc to see what calls are available:
# http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/xmlrpc/XmlRpcService.html
# /home/issues_reminder.py
import xmlrpclib
import time
from time import mktime
from datetime import datetime
from datetime import timedelta
import smtplib,email
from smtplib import SMTP
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
# Jira connction info
server = 'https://your.jira.com/rpc/xmlrpc'
user = 'user'
password = 'password'
filter = '10302' # Filter ID
# Email definitions
smtpserver = 'mail.server.com'
fromAddr = 'support#your.jira.com'
mail_user = 'jira_admin#your.domain.com'
mail_password = 'password'
toAddr = 'support#your.domain.com'
mysubject = "hrs Issue notification!!!"
opend_since_field = "customfield_10101"
COMMASPACE = ', '
def email_issue(issue,esc_time):
# create html email
subject = '['+issue+'] '+esc_time+mysubject
html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
html +='<body style="font-size:12px;font-family:Verdana">'
html +='<p align="center"><img src="your_logo.jpg" alt="logo" height="43" width="198"></p> '
html +='<p> The issue ['+issue+'] is open for over '+esc_time+' hours.</p>'
html +='<p> A link to view the issue: https://your.jira.com/browse/'+issue+'.</p>'
html +='<BR><p> This is an automated email sent from Jira.</p>'
html +='</body></html>'
emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
emailMsg['Subject'] = subject
emailMsg['From'] = fromAddr
emailMsg['To'] = toAddr
emailMsg.attach(MIMEText(html, 'html'))
# Send the email
emailserver = SMTP(smtpserver) # ip or domain name of smtp server
emailserver.login(mail_user, mail_password)
emailserver.sendmail(fromAddr, [toAddr], emailMsg.as_string())
emailserver.quit()
return
s = xmlrpclib.ServerProxy(server)
auth = s.jira1.login(user, password)
esc12List = []
esc24List = []
esc48List = []
issues = s.jira1.getIssuesFromFilter(auth, filter)
print "Modifying issue..."
for issue in issues:
creation = 0;
# get open since time
for customFields in issue['customFieldValues']:
if customFields['customfieldId'] == opend_since_field :
print "found field!"+ customFields['values']
creation = customFields['values']
if (creation == 0):
creation = issue['created']
print "field not found"
creationTime = datetime.fromtimestamp(mktime(time.strptime(creation, '%d/%b/%y %I:%M %p')))
currentTime = datetime.fromtimestamp(mktime(time.gmtime()))
delta = currentTime - creationTime
esc12 = timedelta(hours=12)
esc24 = timedelta(hours=24)
esc48 = timedelta(hours=48)
print "\nchecking issue "+issue['key']
if (delta < esc12):
print "less than 12 hours"
print "not updating"
continue
if (delta < esc24):
print "less than 24 hours"
for customFields in issue['customFieldValues']:
if customFields['customfieldId'] == 'customfield_10412':
if customFields['values'] == '12h':
print "not updating"
break
else:
print "updating !!!"
s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["12h"]})
esc12List.append(issue['key'])
break
continue
if (delta < esc48):
print "less than 48 hours"
for customFields in issue['customFieldValues']:
if customFields['customfieldId'] == 'customfield_10412':
if customFields['values'] == '24h':
print "not updating"
break
else:
print "updating !!!"
s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["24h"]})
esc24List.append(issue['key'])
break
continue
print "more than 48 hours"
for customFields in issue['customFieldValues']:
if customFields['customfieldId'] == 'customfield_10412':
if customFields['values'] == '48h':
print "not updating"
break
else:
print "updating !!!"
s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["48h"]})
esc48List.append(issue['key'])
break
for key in esc12List:
email_issue(key,'12')
for key in esc24List:
email_issue(key,'24')
for key in esc48List:
email_issue(key,'48')
The main pros of this method is that it's highly customizable, and by saving the data to custom fields it's easy to create filters and reports to show issues that have been opened for a long time.
Escalating to the development team
Create a new transition - Escalate. This will create an issue for the development team, and link the new issue to the support issue. Add the following post function:
from com.atlassian.jira.util import ImportUtils
from com.atlassian.jira import ManagerFactory
from com.atlassian.jira.issue import MutableIssue
from com.atlassian.jira import ComponentManager
from com.atlassian.jira.issue.link import DefaultIssueLinkManager
from org.ofbiz.core.entity import GenericValue;
# get issue objects
issueManager = ComponentManager.getInstance().getIssueManager()
issueFactory = ComponentManager.getInstance().getIssueFactory()
authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
issueLinkManager = ComponentManager.getInstance().getIssueLinkManager()
customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
userUtil = ComponentManager.getInstance().getUserUtil()
projectMgr = ComponentManager.getInstance().getProjectManager()
customer_name = customFieldManager.getCustomFieldObjectByName("Customer Name")
customer_email = customFieldManager.getCustomFieldObjectByName("Customer Email")
escalate = customFieldManager.getCustomFieldObjectByName("Escalate to Development")
if issue.getCustomFieldValue(escalate) is not None:
# define issue
issueObject = issueFactory.getIssue()
issueObject.setProject(projectMgr.getProject(10000))
issueObject.setIssueTypeId("1") # bug
# set subtask attributes
issueObject.setSummary("[Escalated from support] "+issue.getSummary())
issueObject.setAssignee(userUtil.getUserObject("nadav"))
issueObject.setReporter(issue.getAssignee())
issueObject.setDescription(issue.getDescription())
issueObject.setCustomFieldValue(customer_name, issue.getCustomFieldValue(customer_name)+" "+issue.getCustomFieldValue(customer_email))
issueObject.setComponents(issue.getComponents())
# Create subtask
subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
# Link parent issue to subtask
issueLinkManager.createIssueLink(issueObject.getId(),issue.getId(),10003,1,authenticationContext.getUser())
# Update search indexes
ImportUtils.setIndexIssues(True);
ComponentManager.getInstance().getIndexManager().reIndex(subTask)
ImportUtils.setIndexIssues(False)
Moving to sales
reate a new transition - Move to sales. Many support calls end up as a sale call, this will move the issue to the sales team. Add the following post function:
from com.atlassian.jira.util import ImportUtils
from com.atlassian.jira.issue import MutableIssue
from com.atlassian.jira import ComponentManager
customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
userUtil = ComponentManager.getInstance().getUserUtil()
issue.setStatusId("1");
issue.setAssignee(userUtil.getUserObject("John"))
issue.setSummary("[Moved from support] "+issue.getSummary())
issue.setProjectId(10201);
issue.setIssueTypeId("35");
ImportUtils.setIndexIssues(True);
ComponentManager.getInstance().getIndexManager().reIndex(issue)
ImportUtils.setIndexIssues(False)
# add to comments
from time import gmtime, strftime
time = strftime("%d-%m-%Y %H:%M:%S", gmtime())
cm = ComponentManager.getInstance().getCommentManager()
currentUser = ComponentManager.getInstance().getJiraAuthenticationContext().getUser().toString()
cm.create(issue,currentUser,'Email was moved to Sales at '+time,False)
Do you recommend Jira also for customer support or should we find
another system like for example Zendesk for that purpose?
Full disclosure: I'm the creator of DoneDone but this question is basically why our product exists.
DoneDone is a simple bug tracker and customer support/shared inbox tool rolled into one. We use it for general customer support (both via our support email address and the contact form on our website). The shared inbox tool lets you have private discussion on emails, along with allowing you to assign, prioritize, tag, and create/change statuses on them (e.g. "Open", "In Progress", etc.)
DoneDone lets you connect customer conversations (a.k.a. incoming support email) to internal tasks. So, if your company has distinct support and client-facing people while also having internal devs and you want to separate their work, you can create any number of subtasks from an incoming conversation.
If your looking for a good way to organize internal work with customer support feedback, it might be worth signing up for a free trial.