I am upgrading current project from channel v1 to v3 and I am bit stuck here
class MultiplexConsumer(WebsocketConsumer):
def connect(self):
print(11111111, self.scope)
logger.debug("Received new connection request from {}", self.channel_name)
WebSocketsConnection.objects.create(channel_id=self.channel_name, last_pong=datetime.datetime.now())
print(444444444)
self.accept()
print(555555555)
...
class WebSocketsConnection(models.Model):
"""
This model exists because Django channels does not provide a default way to handle user presence.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
channel_id = models.CharField(max_length=50)
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.deletion.SET_NULL)
last_pong = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=30, null=True, blank=True)
data = JSONField(default={})
def ping(self):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.send)(self.channel_id, create_action('API', APIConstants.PING), immediately=True)
def pong(self):
self.last_pong = timezone.now()
self.save()
def get_groups(self):
groups = []
for sub in WebSocketsConnectionSubscription.objects.filter(ws_connection=self):
groups.append(sub.get_group_id())
return groups
def _add_subscription(self, data, sub_type):
try:
sub = WebSocketsConnectionSubscription.objects.get(ws_connection=self, type=sub_type)
sub.data = data
sub.save()
except WebSocketsConnectionSubscription.DoesNotExist:
WebSocketsConnectionSubscription.objects.create(ws_connection=self, data=data, type=sub_type)
It never prints 444444444, if I remove the WebSocketsConnection model creation statement, it flows fine. Any ideas?
I checked there are not model signals attached to WebSocketsConnection
I managed to find out the problem, the value of self.channel_name is too long for the field channel_id = models.CharField(max_length=50)
Once I changed it to 100 chars then it worked fine, but why it was not throwing any errors was still unknown.
UPDATE: It's a known problem that consumers not propagating the error up How to see exceptions raised from a channels consumer
I am extremely new to making Discord bots. I am using discordia as my library. Currently, I am making a kick command but for some reason when I attempt to kick the mentioned user, it says "bot.lua:52: attempt to call method 'kick' (a nil value)". However, if I were to attempt to kick the person who sent the message, it works just fine.
client:on("messageCreate", function(msg)
local content = msg.content
local member = msg.member
local channel = msg.guild
local Author = msg.author
if content:sub(1,5) == prefix.."kick" then
local isMod = false
local function checkIfIsMod()
for i, v in pairs(member.roles) do
if v.name:lower() == "admin" then
isMod = true
end
end
end
checkIfIsMod()
if isMod then
print("yes")
if #msg.mentionedUsers > 1 then
msg:reply("Mention one user at a time!")
elseif #msg.mentionedUsers == 0 then
msg:reply("Mention someone!")
elseif #msg.mentionedUsers == 1 then
local mentioned = msg.mentionedUsers[1]
mentioned:kick()
msg:reply("kicked")
end
else
msg:reply("You aren't a mod!")
end
end
end)
I do not understand everything about Discordia, but I have read the documentation and testing and I hope to elucidate the problem now:
Every connected person has two objects known to the bot: User and Member. A user is a Discord account, a member is someone in a server. In real terms: You log into Discord as a user. You are a member of multiple servers.
You cannot kick a User, because a User is not connected to the server. A Member is. kick is a method of Member.
msg.author returns a User, msg.member returns a Member. You say in your post that you are able to kick the person who writes the message. You do not show this code, but I have to assume you are calling kick on msg.member since it would not work on msg.author.
When you mention users, they are returned as a list of IDs (msg.mentionedUsers). Every ID has one user, but a user can be multiple "members" across multiple servers. You need to get the member relationship between the User who is mentioned and the guild (server) the mention is called in. You can do this with Guild:getMember(ID). You could also do this (according to the docs) with Guild.members:get(ID), but this is cached. Offline members are not necessarily cached (known to the method), so I found it safer to use Guild:getMember(ID) (which will make an HTTP request). You can get the guild with msg.guild (as seen in your original code).
Here is working code that iterates over all mentioned users and kicks them. You could rework this to only kick the first person if you wish. You can put this inside your if isMod then statement.
for id in msg.mentionedUsers:iter() do
local u = msg.guild:getMember(id)
print("kicking", u.name)
u:kick()
end
I am new to Shopify app development and ROR. I am working on a Shopify App, Where I need to display the product details along with additional info on a customer page (Front end). From the official doc I understand it can be done using proxy. I have also feeded my proxy URL (URL, sub path etc...) to my app.
And I am able to view my proxy page within my Shopify store. But while I collect custom product list in controller it throws,
ActionView::Template::Error (Failed to open TCP connection to dfbcde0b66b220d0b8b1da94205cea9c:443 (getaddrinfo: Name or service not known))
error. And also the retrieved data could not be accessed in view.
Here is my controller
class PersonalizerController < ApplicationController
include ShopifyApp::AppProxyVerification
include ShopifyAPI
def index
#shop = ShopifyApp::SessionRepository.retrieve(2)
ShopifyAPI::Base.activate_session(#shop)
ShopifyAPI::Shop.current
ShopifyAPI::Base.site = "https://#{ShopifyApp.configuration.api_key}:#"+#shop.token+"##{params[:shop]}/admin"
if(params[:pid].present?)
#fonts = Font.order('id DESC')
#shapes = Shape.order('id DESC')
#clipartcategories = Clipartcategory.order('id DESC')
// This line is causing TCP error
#pdt = ShopifyAPI::Product.find(params[:pid])
#product_id = params[:pid]
#productoption = Productoption.where(product_id: params[:pid])
else
puts "hello"
end
end
end
I am stuck with this for the whole day, any suggestion or Am I miss understood the concept. Kindly clarify.
Your URL is bad
"https://#{ShopifyApp.configuration.api_key}:#"+#shop.token+"##{params[:shop]}/admin"
This is how you do extrapolation in ruby.
"https://#{ShopifyApp.configuration.api_key}:#{#shop.token}#{params[:shop]}/admin"
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.
I am learning how to post data to a web server from Unity3d as a first step towards creating a leaderboard for my game. Right now I have a very simple script in Unity that posts a name and score to my server. The PostScoreURL maps to a create action in Rails (when sent as a POST). It is very simple but works on a basic level.
Unity has a WWW class that I am using to POST to the server. This class has an error property but it is always coming up as 500 Internal Server Error; it has this error if the user is successfully created or if the user is not created due to a validation problem. I would like to add to my Rails app so that I can send more meaningful error messages back to Unity so that the user will know what is going on. For example, if they try to create a user that already exists, they should be notified that they need to use a different name.
Here is my code:
The Unity script:
string PostScoreURL = "http://localhost:3000/users";
string name = "Melanie";
int score = 8732;
WWW www;
bool requestSent = false;
void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 100),"Post Score"))
{
WWWForm form = new WWWForm();
form.AddField("user[name]", name);
form.AddField("user[score]", score);
www = new WWW(PostScoreURL,form);
requestSent = true;
}
if(requestSent && www.isDone)
{
print (www.error);
requestSent = false;
}
}
From the Rails app:
user.rb:
class User < ActiveRecord::Base
attr_accessible :name, :score
validates_presence_of :name, :score
validates_uniqueness_of :name
end
Here is my create action:
def create
#user = User.new(params[:user])
#user.save
end
I would like to send back relevant error messages to Unity. For example: Missing Username, Missing Score, Username taken.
You shouldn't consider your business rule errors as connection errors, that is, those errors should be treated in the server side, returning to the client a "successful" response with an internal error code, defined by you.
I don't know RoR, it probably let you define error codes in the response, but in my case (that don't use RoR) we created a response class with error codes that is serialized and returned to the client. After that, WWW class calls a parser that will verify the error codes. Also, WWW watches for connection errors on WWW.error.