class WriterService(WriterServiceBase): @rpc(M(T), _returns=UnsignedInteger32, _in_message_name='put_%s' % T_name, _in_variable_names={'obj': T_name}) def put(ctx, obj): if obj.id is None: ctx.udc.session.add(obj) ctx.udc.session.flush() # so that we get the obj.id value else: if ctx.udc.session.query(T).get(obj.id) is None: # this is to prevent the client from setting the primary key # of a new object instead of the database's own primary-key # generator. # Instead of raising an exception, you can also choose to # ignore the primary key set by the client by silently doing # obj.id = None in order to have the database assign the # primary key the traditional way. put_not_found(obj.id) else: ctx.udc.session.merge(obj) return obj.id @rpc(M(UnsignedInteger32), _in_message_name='del_%s' % T_name, _in_variable_names={'obj_id': '%s_id' % T_name}) def del_(ctx, obj_id): count = ctx.udc.session.query(T).filter_by(id=obj_id).count() if count == 0: raise ResourceNotFoundError(obj_id) ctx.udc.session.query(T).filter_by(id=obj_id).delete()
class EmailBodyValue(ComplexModel): _type_info = [ ('value', Unicode( doc="String The value of the body part after decoding " "Content-Transfer-Encoding and the Content-Type charset, " "if both known to the server, and with any CRLF replaced with " "a single LF. The server MAY use heuristics to determine the " "charset to use for decoding if the charset is unknown, " "no charset is given, or it believes the charset given is " "incorrect. Decoding is best effort; the server SHOULD insert " "the unicode replacement character (U+FFFD) and continue when " "a malformed section is encountered.\n\n" "Note that due to the charset decoding and line ending " "normalisation, the length of this string will probably not " "be exactly the same as the size property on the " "corresponding EmailBodyPart." )), ('is_encoding_problem', M(Boolean( sub_name='isEncodingProblem', default=False, doc="(default: false) This is true if malformed sections " "were found while decoding the charset, or the charset was " "unknown, or the content-transfer-encoding was unknown.", ))), ('is_truncated', M(Boolean( sub_name='isTruncated', default=False, doc="(default: false) This is true if the value has been " "truncated.", ))), ]
class CrudService(Service): @rpc(M(UnsignedInteger32, _returns=T)) def get(ctx, obj_id): return ctx.udc.session.query(T).filter_by(id=obj_id).one() @rpc(T, _returns=UnsignedInteger32) def put(ctx, obj): if obj.id is None: ctx.udc.session.add(obj) ctx.udc.session.flush() else: if ctx.udc.session.query(T).get(obj.id) is None: raise ResourceNotFoundError('%s.id=%d' % (T_name, obj.id)) else: ctx.udc.session.merge(obj) return obj.id @rpc(M(UnsignedInteger32)) def del_(ctx, obj_id): count = ctx.udc.session.query(T).filter_by(id=obj_id).count() if count == 0: raise ResourceNotFoundError(obj_id) ctx.udc.session.query(T).filter_by(id=obj_id).delete() @rpc(_returns=Iterable(T)) def get_all(ctx): return ctx.udc.session.query(T)
class RandomService(ServiceBase): # We need the _args argument here because we only want to expose the # `a` and `b` arguments and not the `self` argument. randint = srpc(M(Integer), M(Integer), _returns=Integer, _args=('a', 'b'))(random.randint) # We need the _args argument here because `getrandbits` is a builtin, which # means it's not ready for introspection. randbits = srpc(M(UnsignedInteger), _returns=UnsignedInteger, _args=('k',))(random.getrandbits)
class LogEntry(ComplexModel): _type_info = [ ('id', M(Integer64(pk=True))), ('time', M( DateTime( timezone=False, default_factory=lambda: datetime.utcnow(), ))), ('host', IpAddress), ('data', Any), ]
class TimeSegment(ComplexModel, SegmentBase): _SEGMENT_RE = re.compile( u"([\\[\\]])" u"([0-9:\\.]+)" u"," u"([0-9:\\.]+)" u"([\\[\\]])", re.DEBUG | re.UNICODE) _type_info = [ ('start_inclusive', M(Boolean(default=True))), ('start', M(Time)), ('end', M(Time)), ('end_inclusive', M(Boolean(default=True))), ]
def test_integer_values_mandatory_field(self): v = 3 cls = M(Integer(type_name="tn", values=list(range(5)))) assert not cls.get_type_name() is Unicode.Empty elt = _test_type(cls, v).xpath('div/select')[0] assert elt.tag == 'select' assert elt.xpath("option/@value") == [str(vvv) for vvv in range(5)] assert elt.xpath("option[@selected]/text()") == [str(v)]
class B(TableModel): __tablename__ = 'b' __mapper_args__ = { 'polymorphic_on': 't', 'polymorphic_identity': 1, } id = Integer32(pk=True) t = M(Integer32)
class ReaderService(ReaderServiceBase): @rpc(M(UnsignedInteger32), _returns=T, _in_message_name='get_%s' % T_name, _in_variable_names={'obj_id': "%s_id" % T_name}) def get(ctx, obj_id): return ctx.udc.session.query(T).filter_by(id=obj_id).one() @rpc(_returns=Iterable(T), _in_message_name='get_all_%s' % T_name) def get_all(ctx): return ctx.udc.session.query(T).order_by(T.id)
class Preferences(ComplexModel): _type_info = [ ('timezone', M(Unicode(values=pytz.all_timezones_set))), ('font_size', UnsignedInteger8( values_dict={10: 'Small', 20: 'Medium', 30: 'Large'}, default=20, )), ('theme', Unicode( values={'dark', 'light'}, default='light', )), ]
class UserManagerService(Service): @rpc(M(UnsignedInteger32), _returns=User) def get_user(ctx, user_id): return ctx.udc.session.query(User).filter_by(id=user_id).one() @rpc(User, _returns=UnsignedInteger32) def put_user(ctx, user): if user.id is None: ctx.udc.session.add(user) ctx.udc.session.flush() # so that we get the user.id value else: if ctx.udc.session.query(User).get(user.id) is None: # this is to prevent the client from setting the primary key # of a new object instead of the database's own primary-key # generator. # Instead of raising an exception, you can also choose to # ignore the primary key set by the client by silently doing # user.id = None raise ResourceNotFoundError('user.id=%d' % user.id) else: ctx.udc.session.merge(user) return user.id @rpc(M(UnsignedInteger32)) def del_user(ctx, user_id): count = ctx.udc.session.query(User).filter_by(id=user_id).count() if count == 0: raise ResourceNotFoundError(user_id) ctx.udc.session.query(User).filter_by(id=user_id).delete() @rpc(_returns=Iterable(User)) def get_all_user(ctx): return ctx.udc.session.query(User)
class EmailAddress(ComplexModel): _type_info = [ ('name', Unicode(default='')), # sub_name used just to be consistent with EmailAddressGroup ('address', M(Unicode(default='', sub_name='email'))), ] def __eq__(self, other): return self.name == other.name and self.address == other.address def __ne__(self, other): return self.name != other.name or self.address != other.address def is_empty(self): return (self.name is None and self.address is None) \ or (len(self.name) == 0 and len(self.address) == 0)
class D(TableModel): __tablename__ = 'd' id = Integer32(pk=True) i = M(Integer32)
class ws_netpro(ServiceBase): # CANCEL REVERSAL CEK IN @rpc(String, String, s, String, _returns=Boolean) def CancelReversalCekIN(self, dbUser, dbPassword, s, errMessage): path = self.transport.get_path() # get path sepertinya dari URL # import pdb; pdb.set_trace() db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name # res = Resp_CancelReversalCekIN() # res.CancelReversalCekINResult = True # res.errMessage = '' # return res print 'KAPANGGIL DA' yield True @rpc(String, String, s, String, _returns=Boolean) def CancelReversalCekOut(self, dbUser, dbPassword, s, errMessage): path = self.transport.get_path() # get path sepertinya dari URL # import pdb; pdb.set_trace() db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name # res = Resp_CancelReversalCekIN() # res.CancelReversalCekINResult = True # res.errMessage = '' # return res yield True # CEK DATA CHECK IN @rpc(String, String, String, M(String), DateTime, String, String, String, _returns=Resp_CekMemberInClaim) def CekMemberInClaim(self, dbUser, dbPassword, ClaimType, CardNo, sDate, PayTo, errMessage, ResponseCode): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name member_model = registry['netpro.member'] member_id = member_model.search(cr, uid, [('card_no', '=', CardNo)], context=context) res = Resp_CekMemberInClaim() res.CekMemberInClaimResult = True res.errMessage = '' res.ResponseCode = '' return res @rpc(String, String, EDCData, EDCDataOut, String, _returns=Resp_CekDataCheckINResult) def CekDataCheckIN(self, dbUser, dbPassword, EDCData, EDCDataOut, errMsg): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name # create XML # res_bool = etree.Element('CekDataCheckINResult') # res_bool.text = True # res_edc_data_out = etree.Element('EDCDataOut') # BenefitTotalAmount = etree.Element('BenefitTotalAmount') # BenefitTotalAmount.text = '' # res_edc_data_out.append(BenefitTotalAmount) # res_err_msg = etree.Element('errMsg') # res_err_msg.text = '' # # pretty string # a = etree.tostring(res_bool, pretty_print=True) # b = etree.tostring(res_edc_data_out, pretty_print=True) # c = etree.tostring(res_err_msg, pretty_print=True) # yield a, b, c # CekDataCheckINResponse # CekDataCheckINResult # EDCDataOut # errMsg res = Resp_CekDataCheckINResult() res.CekDataCheckINResult = True res.EDCDataOut = EDCDataOut res.errMsg = '' return res # CHECK OUT PATIENT BY EDC @rpc(String, String, EDCData, EDCDataOut, String, _returns=Resp_CheckOutPatientByEDCResult) def CheckOutPatientByEDC(self, dbUser, dbPassword, EDCData, EDCDataOut, errMessage): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_CheckOutPatientByEDCResult() return res # SAVE CLAIM BY EDC @rpc(String, String, EDCData, Integer, String, _returns=Resp_SaveClaimByEDC) def SaveClaimByEDC(self, dbUser, dbPassword, EDCData, cno, errMessage): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_SaveClaimByEDC() return res # GET DATA SET @rpc(String, String, DataSet, String, String, _returns=Resp_GetDataSet) def GetDataSet(self, dbUser, dbPassword, DataSet, SQL, ErrMsg): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_GetDataSet() return res # REVERSAL VOID CEK DATA CHECK IN @rpc(String, String, EDCData, EDCDataOut, String, _returns=Resp_reversalvoidCekDataCheckIN) def reversalvoidCekDataCheckIN(self, dbUser, dbPassword, EDCData, EDCDataOut, errMsg): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_reversalvoidCekDataCheckIN() return res # REVERSAL VOID CHECK OUT PATIENT BY EDC @rpc(String, String, EDCData, EDCDataOut, String, _returns=Resp_reversalvoidCheckOutPatientByEDC) def reversalvoidCheckOutPatientByEDC(self, dbUser, dbPassword, EDCData, EDCDataOut, errmsg): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_reversalvoidCheckOutPatientByEDC() return res # UPDATE SQL @rpc(String, String, String, String, _returns=Resp_UpdateSQL) def UpdateSQL(self, dbUser, dbPassword, SQL, ErrMsg): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_UpdateSQL() return res # CANCEL CEK IN @rpc(String, String, s, String, String, _returns=Resp_CancelCekIN) def UpdateSQL(self, dbUser, dbPassword, s, Tracenumber, errMessage): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_CancelCekIN() return res # CANCEL CEK OUT @rpc(String, String, s, String, String, _returns=Resp_CancelCekOut) def UpdateSQL(self, dbUser, dbPassword, s, Tracenumber, errMessage): path = self.transport.get_path() # get path sepertinya dari URL db_name = path.split('/')[ 2] # pisahkan berdasarkan / dan ambil array ke 3 registry, cr, uid, context = get_registry_cr_uid_context( db_name) # pengambilan registry odoo berdasarkan db name res = Resp_CancelCekOut() return res
class MailCapabilities(ComplexModel): _type_info = [ ('max_mailboxes_per_email', UnsignedInteger( sub_name='maxMailboxesPerEmail', doc="The maximum number of Mailboxes (see " "Section 2) that can be can assigned to a single Email " "object (see Section 4). This MUST be an integer >= 1, " "or null for no limit (or rather, the limit is always the " "number of Mailboxes in the account).")), ('max_mailbox_depth', UnsignedInteger( sub_name='maxMailboxDepth', doc="The maximum depth of the Mailbox hierarchy " "(i.e., one more than the maximum number of ancestors a " "Mailbox may have), or null for no limit.")), ('max_size_mailbox_name', M( UnsignedInteger( sub_name='maxSizeMailboxName', doc="The maximum length, in (UTF-8) octets, allowed " "for the name of a Mailbox. This MUST be at least 100, " "although it is recommended servers allow more."))), ('max_size_attachments_per_email', M( UnsignedInteger( sub_name='maxSizeAttachmentsPerEmail', doc="The maximum total size of attachments, " "in octets, allowed for a single Email object. A server MAY " "still reject the import or creation of an Email with a " "lower attachment size total (for example, if the body " "includes several megabytes of text, causing the size of the " "encoded MIME structure to be over some server-defined " "limit).\n\n" "Note that this limit is for the sum of unencoded attachment " "sizes. Users are generally not knowledgeable about encoding " "overhead, etc., nor should they need to be, so marketing " "and help materials normally tell them the “max size " "attachments”. This is the unencoded size they see on their " "hard drive, so this capability matches that and allows the " "client to consistently enforce what the user understands as " "the limit.\n\n" "The server may separately have a limit for the total size " "of the message [@!RFC5322], created by combining the " "attachments (often base64 encoded) with the message headers " "and bodies. For example, suppose the server advertises " "maxSizeAttachmentsPerEmail: 50000000 (50 MB). The enforced " "server limit may be for a message size of 70000000 octets. " "Even with base64 encoding and a 2 MB HTML body, " "50 MB attachments would fit under this limit."))), ('email_query_sort_options', Array(Unicode, sub_name='emailQuerySortOptions', doc="A list of all the values the server supports for " "the “property” field of the Comparator object in an " "Email/query sort (see Section 4.4.2). This MAY include " "properties the client does not recognise (for example, " "custom properties specified in a vendor extension). Clients " "MUST ignore any unknown properties in the list.")), ('may_create_top_level_mailbox', Boolean(sub_name='mayCreateTopLevelMailbox', doc="If true, the user may create a Mailbox (see Section " "2) in this account with a null parentId. (Permission for " "creating a child of an existing Mailbox is given by the " "myRights property on that Mailbox.)")), ]
class BenchmarkConfig(ComplexModel): framework = M(Unicode) tests = Array(BenchmarkConfigElement, wrapped=False)
class AsyncService(ServiceBase): @rpc(M(UnsignedInteger)) def sleep(ctx, integer): print("Sleeping for %d seconds..." % (integer)) time.sleep(integer)
class SipBuddy(TableModel): __tablename__ = 'cc_sip_buddies' id = Integer32(primary_key=True) defaultip = Unicode(1, db_column='DEFAULTip') accountcode = Unicode(1) allow = Unicode(1) allowtransfer = Unicode(1) amaflags = Unicode(1) auth = Unicode(1) autoframing = Unicode(1) callbackextension = Unicode(1) callerid = Unicode(128) callgroup = Unicode(1) callingpres = Unicode(1) cancallforward = Unicode(1) canreinvite = Unicode(1) cid_number = Unicode(1) context = Unicode(64, default='home') defaultuser = Unicode(64) deny = Unicode(1) disallow = Unicode(1) dtmfmode = Unicode(10, default='rfc2833', values={'info', 'inband', 'rfc2833', 'auto'}) fromdomain = Unicode(1) fromuser = Unicode(1) fullcontact = Unicode host = Unicode(32, index=True, default='dynamic') id_cc_card = Integer32 incominglimit = Unicode(1) insecure = Unicode(1) ipaddr = Unicode(15, index=True) language = Unicode(1) lastms = Unicode mailbox = Unicode(1) mask = Unicode(1) maxcallbitrate = Unicode(1) md5secret = Unicode(1) mohsuggest = Unicode(1) musicclass = Unicode(1) musiconhold = Unicode(1) name = M(Unicode(64, unique=True)) nat = Unicode(1) outboundproxy = Unicode(1) permit = Unicode(1) pickupgroup = Unicode(1) port = Integer32 qualify = Unicode(3, defult='yes', values={'yes', 'no'}) regexten = Unicode(1) regseconds = Integer32 regserver = Unicode(1) restrictcid = Unicode(1) rtpholdtimeout = Unicode(1) rtpkeepalive = Unicode(1) rtptimeout = Unicode(1) secret = Unicode(10) setvar = Unicode(1) subscribecontext = Unicode(1) subscribemwi = Unicode(1) type = Unicode(10, default='friend', values={'friend', 'peer', 'user'}) useragent = Unicode usereqphone = Unicode(1) username = Unicode(64) vmexten = Unicode(1)
class BenchmarkConfigElement(ComplexModel): # exclude this from the output document key = Unicode(pa={JsonDocument: dict(exc=True)}) display_name = M(Unicode) notes = Unicode versus = Unicode db_url = AnyUri json_url = AnyUri query_url = AnyUri fortune_url = AnyUri update_url = AnyUri plaintext_url = AnyUri port = M(UnsignedInteger16(default=8080)) approach = M(Unicode(values=['Realistic', 'Stripped'], default='Realistic')) classification = M( Unicode(values=['Micro', 'Fullstack', 'Platform'], default='Micro')) database = M( Unicode(values=['none', 'mongodb', 'postgres', 'mysql'], default='none')) orm = M(Unicode(values=['Full', 'Micro', 'None', 'Raw'])) framework = M(Unicode) language = M(Unicode) flavor = M(Unicode) platform = M(Unicode) webserver = M(Unicode) os = M(Unicode(default='Linux')) database_os = M(Unicode(default='Linux'))
class EmailBodyPart(ComplexModel): _type_info = [ ('part_id', Unicode( sub_name='partId', doc="Identifies this part uniquely within the Email. This is " "scoped to the emailId and has no meaning outside of the " "JMAP Email object representation. This is null if, and only " "if, the part is of type multipart." )), ('blob_id', JmapId( sub_name='blobId', doc="Id|null The id representing the raw octets of the contents " "of the part, after decoding any known " "Content-Transfer-Encoding (as defined in [@!RFC2045]), or " "null if, and only if, the part is of type multipart. Note " "that two parts may be transfer-encoded differently but have " "the same blob id if their decoded octets are identical and " "the server is using a secure hash of the data for the blob " "id. If the transfer encoding is unknown, it is treated as " "though it had no transfer encoding." )), ('size', M(UnsignedInteger( sub_name='size', doc="UnsignedInt The size, in octets, of the raw data after " "content transfer decoding (as referenced by the blobId, " "i.e., the number of octets in the file the user would " "download)." ))), ('headers', Array(EmailHeader, sub_name='headers', doc="This is a list of all header fields in the " "part, in the order they appear in the message. The values " "are in Raw form." )), ('name', Unicode( sub_name='name', doc="This is the decoded filename parameter of the " "Content-Disposition header field per [@!RFC2231], or (for " "compatibility with existing systems) if not present, " "then it’s the decoded name parameter of the Content-Type " "header field per [@!RFC2047]." )), ('type', M(Unicode( sub_name='type', doc='String The value of the Content-Type header field of the ' 'part, if present; otherwise, the implicit type as per the ' 'MIME standard (text/plain or message/rfc822 if inside a ' 'multipart/digest). CFWS is removed and any parameters are ' 'stripped.' ))), ('charset', Unicode( sub_name='charset', doc="The value of the charset parameter of the Content-Type " "header field, if present, or null if the header field is " "present but not of type text. If there is no Content-Type " "header field, or it exists and is of type text but has no " "charset parameter, this is the implicit charset as per the " "MIME standard: us-ascii." )), ('disposition', Unicode( sub_name='disposition', doc="The value of the Content-Disposition header " "field of the part, if present; otherwise, it’s null. CFWS is " "removed and any parameters are stripped." )), ('cid', Unicode( sub_name='cid', doc="The value of the Content-Id header field of the " "part, if present; otherwise it’s null. CFWS and surrounding " "angle brackets (<>) are removed. This may be used to " "reference the content from within a text/html body part HTML " "using the cid: protocol, as defined in [@!RFC2392]." )), ('language', Array(Unicode, sub_name='language', doc="The list of language tags, as defined in [" "@!RFC3282], in the Content-Language header field of the " "part, if present." )), ('location', Unicode( sub_name='location', doc="The URI, as defined in [@!RFC2557], in the " "Content-Location header field of the part, if present." )), ('subParts', Array(SelfReference, sub_name='subParts', doc="If the type is multipart, this contains the body parts of " "each child." )), ]
class EmailHeader(ComplexModel): _type_info = [ ('key', M(Unicode(default=''))), # sub_name used just to be consistent with EmailAddressGroup ('value', M(Unicode(default='', sub_name='email'))), ]
class EmailAddressGroup(ComplexModel): _type_info = [ ('name', Unicode(default='')), ('addresses', Array(M(Unicode(default='')))), ]
class BenchmarkConfigElement(ComplexModel): # exclude this from the output document key = Unicode(pa={JsonDocument: dict(exc=True)}) display_name = M(Unicode) notes = Unicode versus = Unicode db_url = AnyUri json_url = AnyUri query_url = AnyUri fortune_url = AnyUri update_url = AnyUri plaintext_url = AnyUri port = M(UnsignedInteger16(default=8080)) approach = M(Unicode(values=["Realistic", "Stripped"], default="Realistic")) classification = M( Unicode(values=["Micro", "Fullstack", "Platform"], default="Micro") ) database = M( Unicode(values=["none", "mongodb", "postgres", "mysql"], default="none") ) orm = M(Unicode(values=["Full", "Micro", "None", "Raw"])) framework = M(Unicode) language = M(Unicode) flavor = M(Unicode) platform = M(Unicode) webserver = M(Unicode) os = M(Unicode(default="Linux")) database_os = M(Unicode(default="Linux"))
# obtain a copy from the repository root cited above. # from spyne import M, Unicode, DateTime UtcDate = DateTime(timezone=False) # # Quoting: https://jmap.io/spec-core.html#the-id-data-type # # These characters are safe to use in almost any context (e.g., filesystems, # URIs, and IMAP atoms). For maximum safety, servers SHOULD also follow # defensive allocation strategies to avoid creating risks where glob # completion or data type detection may be present (e.g., on filesystems or # in spreadsheets). In particular, it is wise to avoid: # # - Ids starting with a dash # - Ids starting with digits # - Ids that contain only digits # - Ids that differ only by ASCII case (for example, A vs. a) # - the specific sequence of three characters “NIL” (because this sequence # - can be confused with the IMAP protocol expression of the null value) # # A good solution to these issues is to prefix every id with a single # alphabetical character. # # Hence the lowercase letter as the initial character # JmapId = M(Unicode(255, pattern='[a-z][A-Za-z0-9_-]+'))
class Email(ComplexModel): _type_info = [ # # Metadata # ('id', JmapId( sub_name='id', doc="(immutable; server-set) The id of the Email object. Note " "that this is the JMAP object id, NOT the Message-ID header " "field value of the message [@!RFC5322]." )), ('blob_id', JmapId( sub_name='blobId', doc="(immutable; server-set) The id representing the raw " "octets of the message [@!RFC5322] for this Email. This may " "be used to download the raw original message or to attach it " "directly to another Email, etc." )), ('thread_id', JmapId( sub_name='threadId', doc="(immutable; server-set) The id of the Thread to which " "this Email belongs." )), ('mailbox_ids', AnyDict( # this is supposed to be a JmapId: bool dict sub_name='mailboxIds', doc="The set of Mailbox ids this Email belongs to. An " "Email in the mail store MUST belong to one or more Mailboxes " "at all times (until it is destroyed). The set is represented " "as an object, with each key being a Mailbox id. The value " "for each key in the object MUST be true." )), ('keywords', AnyDict( # this is supposed to be a str: bool dict sub_name='keywords', doc="(default: {}) A set of keywords that apply " "to the Email. The set is represented as an object, with the " "keys being the keywords. The value for each key in the " "object MUST be true." )), ('size', UnsignedInteger( sub_name='size', doc="(immutable; server-set) The size, in octets, " "of the raw data for the message [@!RFC5322] (as referenced " "by the blobId, i.e., the number of octets in the file the " "user would download)." )), ('received_at', UtcDate( default_factory=lambda: datetime.utcnow().replace(tzinfo=pytz.utc) .isoformat(), sub_name='receivedAt', doc="(immutable; default: time of creation on server) The " "date the Email was received by the message store. This is " "the internal date in IMAP [@?RFC3501]." )), # # Header fields # ('message_id', Array(Unicode, sub_name='messageId', doc="(immutable) The value is identical to the " "value of header:Message-ID:asMessageIds. For messages " "conforming to RFC 5322 this will be an array with a single " "entry." )), ('in_reply_to', Array(Unicode, sub_name='inReplyTo', doc="(immutable) The value is identical to the " "value of header:In-Reply-To:asMessageIds." )), ('references', Array(Unicode, sub_name='references', doc="(immutable) The value is identical to the " "value of header:References:asMessageIds." )), ('sender', Array(EmailAddress, sub_name='sender', doc="(immutable) The value is identical to " "the value of header:Sender:asAddresses." )), ('from_', Array(Unicode, sub_name='from', doc="(immutable) The value is identical to " "the value of header:From:asAddresses." )), ('to', Array(Unicode, sub_name='to', doc="(immutable) The value is identical to " "the value of header:To:asAddresses." )), ('cc', Array(Unicode, sub_name='cc', doc="(immutable) The value is identical to " "the value of header:Cc:asAddresses." )), ('bcc', Array(Unicode, sub_name='bcc', doc="(immutable) The value is identical to " "the value of header:Bcc:asAddresses." )), ('reply_to', Unicode( sub_name='replyTo', doc="(immutable) The value is identical to " "the value of header:Reply-To:asAddresses." )), ('subject', Unicode( sub_name='subject', doc="(immutable) The value is identical to the value " "of header:Subject:asText." )), ('sent_at', DateTime( sub_name='sentAt', doc="(immutable; default on creation: current server " "time) The value is identical to the value of " "header:Date:asDate." )), # # Body Parts # ('body_structure', Array(EmailBodyPart, sub_name='bodyStructure', doc="(immutable) This is the full MIME structure of the message " "body, without recursing into message/rfc822 or message/global " "parts. Note that EmailBodyParts may have subParts if they " "are of type multipart." )), ('body_values', AnyDict( sub_name='bodyValues', doc="(immutable) This is a map of partId to an EmailBodyValue " "object for none, some, or all text parts. Which parts are " "included and whether the value is truncated is determined " "by various arguments to Email/get and Email/parse." )), ('text_body', Array(EmailBodyPart, sub_name='textBody', doc="(immutable) A list of text/plain, text/html, image, audio, " "and/or video parts to display (sequentially) as the message " "body, with a preference for text/plain when alternative " "versions are available." )), ('html_body', Array(EmailBodyPart, sub_name='htmlBody', doc="(immutable) A list of text/plain, text/html, image, audio, " "and/or video parts to display (sequentially) as the message " "body, with a preference for text/html when alternative " "versions are available." )), ('attachments', Array(EmailBodyPart, sub_name='attachments', doc="(immutable) A list, traversing depth-first, " "of all parts in bodyStructure that satisfy either of the " "following conditions:" )), ('has_attachment', M(Boolean( sub_name='hasAttachment', default=False, doc="(immutable; server-set) This is true if there are " "one or more parts in the message that a client UI should " "offer as downloadable. A server SHOULD set hasAttachment to " "true if the attachments list contains at least one item that " "does not have Content-Disposition: inline. The server MAY " "ignore parts in this list that are processed automatically " "in some way or are referenced as embedded images in one of " "the text/html parts of the message." ))), ('preview', Unicode(256, sub_name='preview', default=u'', doc="(immutable; server-set) A plaintext fragment of the " "message body. This is intended to be shown as a preview line " "when listing messages in the mail store and may be truncated " "when shown. The server may choose which part of the message " "to include in the preview; skipping quoted sections and " "salutations and collapsing white space can result in a more " "useful preview." )), ]