Merge branch 'edge'
This commit is contained in:
commit
acdac87384
10 changed files with 120 additions and 86 deletions
|
|
@ -226,7 +226,7 @@ def validate_permissions(permissions, for_remove=False):
|
|||
issubmittable = webnotes.conn.get_value("DocType", doctype, "is_submittable")
|
||||
|
||||
def get_txt(d):
|
||||
return "For %s (level %s) in %s:" % (d.role, d.permlevel, d.parent)
|
||||
return "For %s (level %s) in %s row %s:" % (d.role, d.permlevel, d.parent, d.idx)
|
||||
|
||||
def check_atleast_one_set(d):
|
||||
if not d.read and not d.write and not d.submit and not d.cancel and not d.create:
|
||||
|
|
@ -245,7 +245,7 @@ def validate_permissions(permissions, for_remove=False):
|
|||
raise_exception=True)
|
||||
|
||||
def check_level_zero_is_set(d):
|
||||
if d.permlevel > 0 and d.role != 'All':
|
||||
if cint(d.permlevel) > 0 and d.role != 'All':
|
||||
if not permissions.get({"role": d.role, "permlevel": 0}):
|
||||
webnotes.msgprint(get_txt(d) + " Higher level permissions are meaningless if level 0 permission is not set.",
|
||||
raise_exception=True)
|
||||
|
|
|
|||
0
core/doctype/scheduler_log/__init__.py
Normal file
0
core/doctype/scheduler_log/__init__.py
Normal file
8
core/doctype/scheduler_log/scheduler_log.py
Normal file
8
core/doctype/scheduler_log/scheduler_log.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
59
core/doctype/scheduler_log/scheduler_log.txt
Normal file
59
core/doctype/scheduler_log/scheduler_log.txt
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
[
|
||||
{
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"creation": "2013-01-15 12:42:11",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2013-01-15 12:49:23"
|
||||
},
|
||||
{
|
||||
"autoname": "SCHLOG.#####",
|
||||
"description": "Log of Scheduler Errors",
|
||||
"doctype": "DocType",
|
||||
"module": "Core",
|
||||
"document_type": "System",
|
||||
"name": "__common__"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"parent": "Scheduler Log",
|
||||
"doctype": "DocField",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"parentfield": "fields"
|
||||
},
|
||||
{
|
||||
"parent": "Scheduler Log",
|
||||
"read": 1,
|
||||
"cancel": 1,
|
||||
"name": "__common__",
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"submit": 0,
|
||||
"write": 1,
|
||||
"parenttype": "DocType",
|
||||
"role": "System Manager",
|
||||
"report": 1,
|
||||
"permlevel": 0,
|
||||
"parentfield": "permissions"
|
||||
},
|
||||
{
|
||||
"name": "Scheduler Log",
|
||||
"doctype": "DocType"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"label": "Method",
|
||||
"fieldname": "method",
|
||||
"fieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"label": "Error",
|
||||
"fieldname": "error",
|
||||
"fieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm"
|
||||
}
|
||||
]
|
||||
|
|
@ -59,7 +59,7 @@ $.extend(wn.model, {
|
|||
|
||||
if(def_vals[df["default"]])
|
||||
return def_vals[df["default"]];
|
||||
else if(df.fieldtype=="Time" && !df["default"] && df.reqd)
|
||||
else if(df.fieldtype=="Time" && (!df["default"]))
|
||||
return dateutil.get_cur_time()
|
||||
else if(df["default"])
|
||||
return df["default"];
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ wn.views.CommunicationList = Class.extend({
|
|||
make_line: function(doc) {
|
||||
var me = this;
|
||||
var comm = $(repl('<tr><td>\
|
||||
<a href="#Form/Communication/%(name)s" style="font-size: 90%; float: right;">'
|
||||
<a href="#Form/Communication/%(name)s" class="show-details" style="font-size: 90%; float: right;">'
|
||||
+wn._('Show Details')+'</a>\
|
||||
<p class="comm-header" title="'+wn._('Click to Expand / Collapse')+'">\
|
||||
<b>%(_sender)s on %(when)s</b></p>\
|
||||
|
|
@ -83,6 +83,10 @@ wn.views.CommunicationList = Class.extend({
|
|||
padding: 10px; overflow-x: auto; display: none;"></div>\
|
||||
</td></tr>', doc))
|
||||
.appendTo(this.body);
|
||||
|
||||
if(!doc.name) {
|
||||
comm.find(".show-details").toggle(false);
|
||||
}
|
||||
|
||||
comm.find(".comm-header")
|
||||
.css({"cursor":"pointer"})
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class ModelWrapper:
|
|||
self.load_from_db(dt, dn)
|
||||
elif isinstance(dt, list):
|
||||
self.set_doclist(dt)
|
||||
elif isinstance(dt, dict):
|
||||
self.set_doclist([dt])
|
||||
|
||||
def load_from_db(self, dt=None, dn=None, prefix='tab'):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -59,19 +59,7 @@ def get_fullname(profile):
|
|||
|
||||
return profile
|
||||
|
||||
# TODO: deprecate it
|
||||
def decode_email_header(s):
|
||||
import email.header
|
||||
|
||||
# replace double quotes with blank
|
||||
# double quotes in header prohibit decoding of header
|
||||
decoded_header_tuple = email.header.decode_header(s.replace('"', ''))
|
||||
|
||||
decoded_list = map(lambda h: unicode(h[0], encoding=h[1] or 'utf-8'), decoded_header_tuple)
|
||||
|
||||
return " ".join(decoded_list)
|
||||
|
||||
def get_email_id(user):
|
||||
def get_formatted_email(user):
|
||||
"""get email id of user formatted as: John Doe <johndoe@example.com>"""
|
||||
if user == "Administrator":
|
||||
return user
|
||||
|
|
@ -81,14 +69,15 @@ def get_email_id(user):
|
|||
|
||||
def extract_email_id(email):
|
||||
"""fetch only the email part of the email id"""
|
||||
import re
|
||||
sender_email = re.findall("<([^>]*)>", email)
|
||||
return sender_email and sender_email[0] or ""
|
||||
from email.utils import parseaddr
|
||||
if ',' in email and email.count("@")==1:
|
||||
email = email.split(",")[-1]
|
||||
fullname, email_id = parseaddr(email)
|
||||
return email_id
|
||||
|
||||
def validate_email_add(email_str):
|
||||
"""Validates the email string"""
|
||||
from email.utils import parseaddr
|
||||
real_name, email = parseaddr(email_str)
|
||||
email = extract_email_id(email_str)
|
||||
import re
|
||||
return re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", email.lower())
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@
|
|||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
"""
|
||||
This module contains classes for managing incoming emails
|
||||
"""
|
||||
from webnotes.utils import extract_email_id
|
||||
|
||||
class IncomingMail:
|
||||
"""
|
||||
|
|
@ -41,18 +39,21 @@ class IncomingMail:
|
|||
self.html_content = ''
|
||||
self.attachments = []
|
||||
self.parse()
|
||||
self.set_content_and_type()
|
||||
self.from_email = extract_email_id(self.mail["From"])
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
Extracts text, html and attachments from the mail
|
||||
"""
|
||||
for part in self.mail.walk():
|
||||
self.process_part(part)
|
||||
|
||||
def set_content_and_type(self):
|
||||
self.content, self.content_type = '[Blank Email]', 'text/plain'
|
||||
if self.text_content:
|
||||
self.content, self.content_type = self.text_content, 'text/plain'
|
||||
else:
|
||||
self.content, self.content_type = self.html_content, 'text/html'
|
||||
|
||||
def process_part(self, part):
|
||||
"""
|
||||
Process a single part of an email
|
||||
"""
|
||||
content_type = part.get_content_type()
|
||||
charset = part.get_content_charset()
|
||||
if not charset: charset = self.get_charset(part)
|
||||
|
|
@ -67,15 +68,9 @@ class IncomingMail:
|
|||
self.get_attachment(part, charset)
|
||||
|
||||
def get_text_content(self):
|
||||
"""
|
||||
Returns the text parts of the email. If None, then HTML parts
|
||||
"""
|
||||
return self.text_content or self.html_content
|
||||
|
||||
def get_charset(self, part):
|
||||
"""
|
||||
Guesses character set
|
||||
"""
|
||||
charset = part.get_content_charset()
|
||||
if not charset:
|
||||
import chardet
|
||||
|
|
@ -84,57 +79,48 @@ class IncomingMail:
|
|||
return charset
|
||||
|
||||
def get_payload(self, part, charset):
|
||||
"""
|
||||
get utf-8 encoded part content
|
||||
"""
|
||||
try:
|
||||
return unicode(part.get_payload(decode=True),str(charset),"ignore")
|
||||
except LookupError, e:
|
||||
return part.get_payload()
|
||||
|
||||
def get_attachment(self, part, charset):
|
||||
"""
|
||||
Extracts an attachment
|
||||
"""
|
||||
self.attachments.append({
|
||||
'content-type': part.get_content_type(),
|
||||
'filename': part.get_filename(),
|
||||
'content': part.get_payload(decode=True),
|
||||
})
|
||||
|
||||
|
||||
def save_attachments_in_doc(self, doc):
|
||||
from webnotes.utils.file_manager import save_file, add_file_list
|
||||
for attachment in self.attachments:
|
||||
fid = save_file(attachment['filename'], attachment['content'])
|
||||
status = add_file_list(doc.doctype, doc.name, fid, fid)
|
||||
|
||||
def get_thread_id(self):
|
||||
"""
|
||||
Extracts thread id of the message between first []
|
||||
from the subject
|
||||
"""
|
||||
import re
|
||||
subject = self.mail.get('Subject', '')
|
||||
|
||||
return re.findall('(?<=\[)[\w/-]+', subject)
|
||||
l= re.findall('(?<=\[)[\w/-]+', subject)
|
||||
return l and l[0] or None
|
||||
|
||||
class POP3Mailbox:
|
||||
"""
|
||||
A simple pop3 mailbox, abstracts connection and mail extraction
|
||||
To use, subclass it and override method process_message(from, subject, text, thread_id)
|
||||
"""
|
||||
def __init__(self):
|
||||
self.setup()
|
||||
self.get_messages()
|
||||
|
||||
def __init__(self, settings_doc):
|
||||
"""
|
||||
settings_doc must contain
|
||||
use_ssl, host, username, password
|
||||
(by name or object)
|
||||
"""
|
||||
if isinstance(settings_doc, basestring):
|
||||
from webnotes.model.doc import Document
|
||||
self.settings = Document(settings_doc, settings_doc)
|
||||
else:
|
||||
self.settings = settings_doc
|
||||
def setup(self):
|
||||
# overrride
|
||||
self.settings = webnotes._dict()
|
||||
|
||||
def check_mails(self):
|
||||
# overrride
|
||||
return True
|
||||
|
||||
def process_message(self, mail):
|
||||
# overrride
|
||||
pass
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
Connects to the mailbox
|
||||
"""
|
||||
import poplib
|
||||
|
||||
if self.settings.use_ssl:
|
||||
|
|
@ -145,10 +131,6 @@ class POP3Mailbox:
|
|||
self.pop.pass_(self.settings.password)
|
||||
|
||||
def get_messages(self):
|
||||
"""
|
||||
Loads messages from the mailbox and calls
|
||||
process_message for each message
|
||||
"""
|
||||
import webnotes
|
||||
|
||||
if not self.check_mails():
|
||||
|
|
@ -190,15 +172,3 @@ class POP3Mailbox:
|
|||
self.pop.quit()
|
||||
webnotes.conn.begin()
|
||||
|
||||
def check_mails(self):
|
||||
"""
|
||||
To be overridden
|
||||
If mailbox is to be scanned, returns true
|
||||
"""
|
||||
return True
|
||||
|
||||
def process_message(self, mail):
|
||||
"""
|
||||
To be overriden
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -101,8 +101,10 @@ def log(method):
|
|||
|
||||
import webnotes.utils
|
||||
webnotes.conn.begin()
|
||||
webnotes.conn.sql("""insert into __SchedulerLog (`timestamp`, method, error)
|
||||
values (%s, %s, %s)""", (webnotes.utils.now_datetime(), method, traceback))
|
||||
d = webnotes.doc("Scheduler Log")
|
||||
d.method = method
|
||||
d.error = traceback
|
||||
d.save()
|
||||
webnotes.conn.commit()
|
||||
|
||||
return traceback
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue