多租户更改
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
||||
"""Utility functions for tn-cli."""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import base64
|
||||
import json
|
||||
from PIL import Image
|
||||
try:
|
||||
from io import BytesIO as memory_io
|
||||
except ImportError:
|
||||
from cStringIO import StringIO as memory_io
|
||||
import mimetypes
|
||||
import os
|
||||
|
||||
from tn_globals import stdoutln
|
||||
|
||||
# Maximum in-band (included directly into the message) attachment size which fits into
|
||||
# a message of 256K in size, assuming base64 encoding and 1024 bytes of overhead.
|
||||
# This is size of an object *before* base64 encoding is applied.
|
||||
MAX_INBAND_ATTACHMENT_SIZE = 195840
|
||||
|
||||
# Absolute maximum attachment size to be used with the server = 8MB.
|
||||
MAX_EXTERN_ATTACHMENT_SIZE = 1 << 23
|
||||
|
||||
# Maximum allowed linear dimension of an inline image in pixels.
|
||||
MAX_IMAGE_DIM = 768
|
||||
|
||||
# String used as a delete marker. I.e. when a value needs to be deleted, use this string
|
||||
DELETE_MARKER = 'DEL!'
|
||||
|
||||
# Unicode DEL character used internally by Tinode when a value needs to be deleted.
|
||||
TINODE_DEL = '␡'
|
||||
|
||||
|
||||
# Python is retarded.
|
||||
class dotdict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
__getattr__ = dict.get
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
|
||||
# Pack name, description, and avatar into a theCard.
|
||||
def makeTheCard(fn, note, photofile):
|
||||
card = None
|
||||
|
||||
if (fn != None and fn.strip() != "") or photofile != None or note != None:
|
||||
card = {}
|
||||
if fn != None:
|
||||
fn = fn.strip()
|
||||
card['fn'] = TINODE_DEL if fn == DELETE_MARKER or fn == '' else fn
|
||||
|
||||
if note != None:
|
||||
note = note.strip()
|
||||
card['note'] = TINODE_DEL if note == DELETE_MARKER or note == '' else note
|
||||
|
||||
if photofile != None:
|
||||
if photofile == '' or photofile == DELETE_MARKER:
|
||||
# Delete the avatar.
|
||||
card['photo'] = {
|
||||
'data': TINODE_DEL
|
||||
}
|
||||
else:
|
||||
try:
|
||||
f = open(photofile, 'rb')
|
||||
# File extension is used as a file type
|
||||
mimetype = mimetypes.guess_type(photofile)
|
||||
if mimetype[0]:
|
||||
mimetype = mimetype[0].split("/")[1]
|
||||
else:
|
||||
mimetype = 'jpeg'
|
||||
data = base64.b64encode(f.read())
|
||||
# python3 fix.
|
||||
if type(data) is not str:
|
||||
data = data.decode()
|
||||
card['photo'] = {
|
||||
'data': data,
|
||||
'type': mimetype
|
||||
}
|
||||
f.close()
|
||||
except IOError as err:
|
||||
stdoutln("Error opening '" + photofile + "':", err)
|
||||
|
||||
return card
|
||||
|
||||
|
||||
# Create drafty representation of a message with an inline image.
|
||||
def inline_image(filename):
|
||||
try:
|
||||
im = Image.open(filename, 'r')
|
||||
width = im.width
|
||||
height = im.height
|
||||
format = im.format if im.format else "JPEG"
|
||||
if width > MAX_IMAGE_DIM or height > MAX_IMAGE_DIM:
|
||||
# Scale the image
|
||||
scale = min(min(width, MAX_IMAGE_DIM) / width, min(height, MAX_IMAGE_DIM) / height)
|
||||
width = int(width * scale)
|
||||
height = int(height * scale)
|
||||
resized = im.resize((width, height))
|
||||
im.close()
|
||||
im = resized
|
||||
|
||||
mimetype = 'image/' + format.lower()
|
||||
bitbuffer = memory_io()
|
||||
im.save(bitbuffer, format=format)
|
||||
data = base64.b64encode(bitbuffer.getvalue())
|
||||
|
||||
# python3 fix.
|
||||
if type(data) is not str:
|
||||
data = data.decode()
|
||||
|
||||
result = {
|
||||
'txt': ' ',
|
||||
'fmt': [{'len': 1}],
|
||||
'ent': [{'tp': 'IM', 'data':
|
||||
{'val': data, 'mime': mimetype, 'width': width, 'height': height,
|
||||
'name': os.path.basename(filename)}}]
|
||||
}
|
||||
im.close()
|
||||
return result
|
||||
except IOError as err:
|
||||
stdoutln("Failed processing image '" + filename + "':", err)
|
||||
return None
|
||||
|
||||
|
||||
# Create a drafty message with an *in-band* attachment.
|
||||
def attachment(filename):
|
||||
try:
|
||||
f = open(filename, 'rb')
|
||||
# Try to guess the mime type.
|
||||
mimetype = mimetypes.guess_type(filename)[0]
|
||||
data = base64.b64encode(f.read())
|
||||
# python3 fix.
|
||||
if type(data) is not str:
|
||||
data = data.decode()
|
||||
result = {
|
||||
'fmt': [{'at': -1}],
|
||||
'ent': [{'tp': 'EX', 'data':{
|
||||
'val': data, 'mime': mimetype, 'name':os.path.basename(filename)
|
||||
}}]
|
||||
}
|
||||
f.close()
|
||||
return result
|
||||
except IOError as err:
|
||||
stdoutln("Error processing attachment '" + filename + "':", err)
|
||||
return None
|
||||
|
||||
|
||||
# encode_to_bytes converts the 'src' to a byte array.
|
||||
# An object/dictionary is first converted to json string then it's converted to bytes.
|
||||
# A string is directly converted to bytes.
|
||||
def encode_to_bytes(src):
|
||||
if src == None:
|
||||
return None
|
||||
if isinstance(src, str):
|
||||
return ('"' + src + '"').encode()
|
||||
return json.dumps(src).encode('utf-8')
|
||||
|
||||
|
||||
# Parse credentials
|
||||
def parse_cred(cred):
|
||||
result = None
|
||||
if cred != None:
|
||||
result = []
|
||||
for c in cred.split(","):
|
||||
parts = c.split(":")
|
||||
from tinode_grpc import pb
|
||||
result.append(pb.ClientCred(method=parts[0] if len(parts) > 0 else None,
|
||||
value=parts[1] if len(parts) > 1 else None,
|
||||
response=parts[2] if len(parts) > 2 else None))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Parse trusted values: [staff,rm-verified].
|
||||
def parse_trusted(trusted):
|
||||
result = None
|
||||
if trusted != None:
|
||||
result = {}
|
||||
for t in trusted.split(","):
|
||||
t = t.strip()
|
||||
if t.startswith("rm-"):
|
||||
result[t[3:]] = False
|
||||
else:
|
||||
result[t] = True
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user