336 lines
19 KiB
Python
336 lines
19 KiB
Python
import ast
|
|
import datetime
|
|
import json
|
|
import re
|
|
import uuid
|
|
import logging
|
|
import base64
|
|
import subprocess
|
|
import tempfile
|
|
import easywebdav
|
|
import os
|
|
import os.path
|
|
import requests
|
|
import hashlib
|
|
from PIL import Image,ImageDraw,ImageFont
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo import tools
|
|
from odoo.exceptions import ValidationError
|
|
from datetime import date
|
|
from datetime import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
from pyffmpeg import FFmpeg
|
|
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
|
|
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
|
|
from webdav4.client import Client
|
|
from webdav4.fsspec import WebdavFileSystem
|
|
import sys
|
|
|
|
TUYA_LOGGER.setLevel(logging.DEBUG)
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class dssbinaries(models.Model):
|
|
|
|
@api.model
|
|
def create(self,vals):
|
|
result = super().create(vals)
|
|
return result
|
|
|
|
_name = "dss.binaries"
|
|
_description = "DigitalSignage Dateien"
|
|
# _inherit = ['mail.thread','mail.activity.mixin']
|
|
_rec_name = "binary_id"
|
|
# _inherit = ['mail.thread', 'mail.activity.mixin']
|
|
|
|
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
|
|
date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date())
|
|
date_lastedit = fields.Date('Änderungsdatum')
|
|
user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user())
|
|
user_lastedit = fields.Char('Änderungsuser')
|
|
binary_id = fields.Char(string="Binary ID", required=True, help = "Das ist eine eindeutige ID für diese Dateityp. Sie wird automatisch generiert und sollte nicht manuell geändert werden.", default=lambda self: self._default_binary_id())
|
|
binary_name = fields.Char(string="Binary Name", required=True, help = "Der Name des Dateityp, die Sie hochladen möchten. Dieser Name wird in der Benutzeroberfläche angezeigt.")
|
|
binary_mediatype = fields.Many2one('dss.mediatypes', string="Binary Mediatype", required=True, help = "Der Mediatyp, der für diese Datei verwendet werden soll. Dies kann z.B. 'Video', 'Bild' oder 'Audio' sein.")
|
|
binary_mediatype_can_gen_stamp = fields.Boolean(related='binary_mediatype.can_gen_stamp')
|
|
binary_mediatype_name = fields.Char(related='binary_mediatype.medianame', string="Mediatype Name", store=True, help = "Der Name des Mediatyps, der für diese Datei verwendet wird. Dies wird automatisch aus dem Mediatypen-Feld abgerufen")
|
|
binary_mediatype_def_filename = fields.Char(related='binary_mediatype.filepartname', string="Mediatype Default Dateiname", help = "Der Standard-Dateiname für diesen Mediatyp. Dies wird automatisch aus dem Mediatypen-Feld abgerufen")
|
|
binary_binary = fields.Binary(string="Binary Datei", help = "Die eigentliche Datei, die Sie hochladen möchten. Diese Datei wird in der Datenbank und Cloud gespeichert")
|
|
binary_binary_t = fields.Binary(string="Binary Temp Datei", help = "Die eigentliche Datei, die Sie hochladen möchten. Diese Datei wird in der Datenbank und Cloud gespeichert.")
|
|
binary_filename = fields.Char(string="Binary Dateiname", help = "Der Name der hochgeladenen Datei. Dies wird automatisch aus dem Dateinamen der hochgeladenen Datei abgerufen.",compute="_compute_binary_filename", store=True)
|
|
binary_type = fields.Char(string="Binary Typ", help = "Der Typ den die hochgeladenen Datei haben sollte.")
|
|
binary_cloud_link = fields.Char(string="Cloud Link", help = "Der Link zur Datei in der Cloud, wenn die Datei in der Cloud gespeichert ist.")
|
|
binary_size = fields.Integer(string="Binary Größe", help = "Die Größe der hochgeladenen Datei in Bytes.")
|
|
binary_description = fields.Text(string="Binary Beschreibung", help = "Eine Beschreibung der hochgeladenen Datei. Dies kann Informationen über den Inhalt der Datei, den Verwendungszweck oder andere relevante Details enthalten.")
|
|
binary_issaved = fields.Boolean(string="Binary Gespeichert", default=False, help = "Ein Flag, das angibt, ob die Datei in der Datenbank und Cloud gespeichert ist. Wenn dies aktiviert ist, wird die Datei in der Datenbank und Cloud gespeichert.")
|
|
binary_secured_ro = fields.Boolean(string="Gesperrt", default=False, help = "Ein Flag, das angibt, ob die Datei gesperrt ist. Wenn dies aktiviert ist, kann die Datei nicht mehr bearbeitet oder gelöscht werden. Sie wird dann auch nicht in Übertragungen oder Ansichten beachtet.")
|
|
binary_used_ro = fields.Boolean(string="Genutzt", default=False, help = "Ein Flag, das angibt, ob die Datei in einer Übertragung/Ausstrahlung verwendet wird. Wenn dies aktiviert ist, kann die Datei nicht mehr gelöscht oder überarbeitet werden.")
|
|
binary_contract = fields.Many2one('dss.contracts', string="Vertrag", help = "Der Vertrag, zu dem diese Datei gehört. Dies kann verwendet werden, um Dateien zu organisieren und zu verwalten, die mit bestimmten Verträgen verbunden sind.")
|
|
|
|
|
|
|
|
@api.depends('binary_binary')
|
|
@api.onchange('binary_binary')
|
|
def _compute_binary_filename(self):
|
|
"""Compute the binary filename based on the uploaded file."""
|
|
_logger.info("Binary getting Filename - B_"+str(self.id))
|
|
if len(self)>0:
|
|
for record in self:
|
|
if record.binary_binary:
|
|
# Extract the filename from the binary content
|
|
extension = 'jpg' # Default extension
|
|
if isinstance(self.binary_binary, str):
|
|
filedata = base64.b64decode(self.binary_binary.split("base64,")[-1])
|
|
else:
|
|
filedata = base64.b64decode(self.binary_binary)
|
|
filedataStr = str(filedata)
|
|
_logger.info("Binary getting Filename - B_"+str(self.id)+" - ["+str(filedataStr[0:23])+"]")
|
|
if filedataStr[0:12] == "b'\\x89PNG\\":
|
|
extension = 'png'
|
|
elif filedataStr[0:17] == "b'\\xff\\xd8\\xff":
|
|
extension = 'jpg'
|
|
elif filedataStr[0:8] == "b'GIF89a":
|
|
extension = 'gif'
|
|
elif filedataStr[0:22] == "b'\\x49\\x49\\x2a\\x00":
|
|
extension = 'tif'
|
|
elif filedataStr[0:27] == "b'\\x25\\x50\\x44\\x46\\x2d":
|
|
extension = 'pdf'
|
|
elif filedataStr[0:23] == "b'\\x00\\x00\\x00 ftypisom":
|
|
extension = 'mp4'
|
|
elif filedataStr[0:22] == "b'\\x00\\x00\\x00\\x18ftyp":
|
|
extension = 'mp4'
|
|
elif filedataStr[0:12] == "b'\\x42\\x4d":
|
|
extension = 'bmp'
|
|
record.binary_filename = f"{record.binary_mediatype.filepartname}{record.binary_contract.contract_auto_id}.{extension}"
|
|
|
|
@api.model
|
|
def _default_uuid(self):
|
|
return str(uuid.uuid4())
|
|
|
|
@api.model
|
|
def _default_create_date(self):
|
|
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
|
|
@api.model
|
|
def _default_create_user(self):
|
|
return self.env.user.name if self.env.user else 'System'
|
|
|
|
@api.model
|
|
def _default_binary_id(self):
|
|
# Generate a unique binary ID based on the current timestamp and a random UUID
|
|
return f"Datei_{str(uuid.uuid4())[:8]}"
|
|
|
|
@api.onchange('binary_binary')
|
|
def _onchange_binary_binary(self):
|
|
"""Update binary size and type when binary content is changed."""
|
|
_logger.info("New Binary B_"+str(self.id))
|
|
existing_binary = False
|
|
if not self._origin.binary_binary:
|
|
existing_binary = False
|
|
else:
|
|
existing_binary = True
|
|
|
|
if not self.binary_contract.cloudlink:
|
|
raise ValidationError(_("Der Vertrag hat keinen Cloudlink. Bitte überprüfen Sie den Vertrag."))
|
|
cloudpath = str(self.binary_contract.cloudlink)
|
|
_logger.info("New Binary checking Cloudlink B_"+str(self.id)+" - "+str(cloudpath))
|
|
cloudpath = cloudpath + '/' + str(self.binary_mediatype.cloudlink)
|
|
client = Client("https://cloud.logumedia.de/remote.php/dav/files/OdooDav/", auth=("odooClient@logumedia.de", "lm2020#OdooDav"))
|
|
_logger.info("New Binary checking Cloudlink for cont : "+str(cloudpath))
|
|
cloudexists = False
|
|
if client.exists(cloudpath):
|
|
# Convert self.binary_binary to bytes-like object
|
|
if isinstance(self.binary_binary, str):
|
|
filedata = base64.b64decode(self.binary_binary.split("base64,")[-1])
|
|
else:
|
|
filedata = base64.b64decode(self.binary_binary)
|
|
filedataStr = str(filedata)
|
|
_logger.info("New Binary Cloudlink exists - Saving File - B_"+str(self.id)+" - "+str(cloudpath)+" - " + str(filedata)+' - ' + filedataStr[0:8])
|
|
try:
|
|
decoded_data = filedata
|
|
except base64.binascii.Error as e:
|
|
if 'Incorrect padding' in str(e):
|
|
filedataStr += b'=' * (4 - len(filedataStr) % 4)
|
|
decoded_data = base64.b64decode(filedataStr)
|
|
if filedataStr[0:10] == "b'\x89PNG":
|
|
extension = 'png'
|
|
else:
|
|
extension = 'jpg'
|
|
_logger.info("New Binary Cloudlink exists - Saving File - B_"+str(self.id)+" - "+str(cloudpath)+" - " + str(base64.b64encode(decoded_data)))
|
|
##infile = open('/tmp/'+filename, "w+b")
|
|
#infile = tempfile.NamedTemporaryFile(delete=False)
|
|
##infile.write(filedata)
|
|
##client.upload_fileobj(infile, f"{cloudpath}/{filename}")
|
|
##infile.close()
|
|
##infile.delete() # Delete the temporary file after upload
|
|
cloudexists = True
|
|
else:
|
|
_logger.info("New Binary Cloudlink does not exists B_"+str(self.id)+" - "+str(cloudpath))
|
|
raise ValidationError(_("Der Cloudlink im Vertrag ist nicht vorhanden. Bitte überprüfen Sie den Link ggf. anlegen."))
|
|
|
|
if cloudexists:
|
|
if self.binary_binary:
|
|
# Calculate the size of the binary content
|
|
self.binary_size = len(filedata)
|
|
# Determine the file type based on the binary content
|
|
self.binary_cloud_link = f"{cloudpath}/{self.binary_filename}"
|
|
self.binary_issaved = True
|
|
else:
|
|
self.binary_size = 0
|
|
self.binary_type = ''
|
|
self.binary_cloud_link = ''
|
|
self.binary_issaved = False
|
|
|
|
|
|
def dload(self):
|
|
"""Download the binary file."""
|
|
if not self.binary_binary:
|
|
raise ValidationError(_("No binary file to download."))
|
|
|
|
# Create a temporary file to store the downloaded content
|
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=self.binary_filename)
|
|
temp_file.write(base64.b64decode(self.binary_binary))
|
|
temp_file.close()
|
|
|
|
# Return the file for download
|
|
return {
|
|
'type': 'ir.actions.act_url',
|
|
'url': f'/web/content/{self.id}/{self.binary_filename}?download=true&filename={self.binary_filename}',
|
|
'target': 'self',
|
|
}
|
|
|
|
def dedit(self):
|
|
"""Edit the binary file."""
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'dss.binaries',
|
|
'view_mode': 'form',
|
|
'res_id': self.id,
|
|
'target': 'new',
|
|
}
|
|
|
|
def resend(self):
|
|
"""Resend the binary file to the contract's partner email."""
|
|
if not self.binary_contract:
|
|
raise ValidationError(_("No contract associated with this binary file."))
|
|
if not self.binary_contract.project.standortpartner:
|
|
raise ValidationError(_("No partner associated with the contract."))
|
|
if not self.binary_contract.project.standortpartner.email:
|
|
raise ValidationError(_("The partner does not have an email address."))
|
|
# Send email with the binary file as attachment
|
|
|
|
def genstamp(self):
|
|
_logger.info('Create Stamps for Binary: B_'+str(self.id)+' '+str(id))
|
|
# Bildparameter definieren
|
|
Medium = self.binary_mediatype
|
|
if Medium and Medium.can_gen_stamp and self.binary_contract:
|
|
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Medium : M_'+str(Medium.id)+' - '+str(Medium.medianame))
|
|
# Bildgröße und Hintergrundfarbe festlegen
|
|
background_color = (255, 255, 255) # Weißer Hintergrund (RGB)
|
|
# Neues Bild erstellen
|
|
maxh = Medium.maxsize_h
|
|
maxw = Medium.maxsize_w
|
|
image = Image.new("RGB", (maxw, maxh), background_color)
|
|
d = ImageDraw.Draw(image)
|
|
Zeilen = Medium.maxsize_h // 6
|
|
zposy = 2
|
|
if self.binary_contract.client:
|
|
text = self.binary_contract.contact_company_name
|
|
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Medium : M_'+str(Medium.id)+' - Text1: '+str(text))
|
|
if len(text) > 35:
|
|
# Trenne den Text an einem Leerzeichen nahe bei Position 40
|
|
idx = text.rfind(' ', 0, 35)
|
|
if idx == -1:
|
|
idx = 35
|
|
text2 = text[:idx]
|
|
bcount = len(text2) if text2 else 1
|
|
fonts = maxw // (bcount ) *1.8
|
|
if fonts > maxh:
|
|
fonts = maxh - 10
|
|
if fonts <=0 :
|
|
fonts = 10
|
|
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
|
|
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
|
|
d.text((maxw // 2, 1*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
|
|
text = text[idx:]
|
|
zposy = 2
|
|
if len(text) > 35:
|
|
# Trenne den Text an einem Leerzeichen nahe bei Position 40
|
|
idx = text.rfind(' ', 0, 35)
|
|
if idx == -1:
|
|
idx = 35
|
|
text2 = text[:idx]
|
|
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
|
|
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
|
|
d.text((maxw // 2, zposy*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
|
|
text = text[idx:]
|
|
zposy = 3
|
|
else:
|
|
bcount = len(text) if text else 1
|
|
fonts = maxw // (bcount ) *1.8
|
|
if fonts > maxh:
|
|
fonts = maxh - 10
|
|
if fonts <=0 :
|
|
fonts = 10
|
|
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
|
|
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
|
|
d.text((maxw // 2, zposy*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
|
|
text = self.binary_contract.contact_street
|
|
bcount = len(text) if text else 1
|
|
Zeilen = maxh // 6
|
|
fonts = maxw // (bcount ) *1.2
|
|
if fonts > maxh:
|
|
fonts = maxh - 10
|
|
if fonts <=0 :
|
|
fonts = 10
|
|
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
|
|
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
|
|
d.text((maxw // 2, 4*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
|
|
text = self.binary_contract.contact_zip+' '+self.binary_contract.contact_city
|
|
bcount = len(text) if text else 1
|
|
Zeilen = maxh // 6
|
|
fonts = maxw // (bcount ) *1.2
|
|
if fonts > maxh:
|
|
fonts = maxh - 10
|
|
if fonts <=0 :
|
|
fonts = 10
|
|
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
|
|
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
|
|
d.text((maxw // 2, 5*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
|
|
# Bild speichern
|
|
filename = Medium.filepartname+self.binary_contract.contract_auto_id+".png"
|
|
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Feld : F_'+str(Medium.id)+' - Filename: '+str(filename))
|
|
image.save(filename)
|
|
_logger.info("Stamp file created "+str(filename))
|
|
_logger.info("Copy file to Binaries B_"+str(self))
|
|
try:
|
|
self.binary_binary = base64.b64encode(open(filename, "rb").read())
|
|
self.binary_filename = filename
|
|
self.binary_type = 'image/png'
|
|
self.binary_size = os.path.getsize(filename)
|
|
self.binary_issaved = False
|
|
self.binary_secured_ro = False
|
|
self.binary_used_ro = False
|
|
finally:
|
|
_logger.info("Binary inserted "+str(self))
|
|
cloudpath = self.binary_contract.cloudlink
|
|
if not cloudpath:
|
|
raise ValidationError(_("Der Vertrag hat keinen Cloudlink. Bitte überprüfen Sie den Vertrag."))
|
|
if not Medium.cloudlink:
|
|
raise ValidationError(_("Der Mediatyp hat keinen Cloudlink. Bitte überprüfen Sie den Mediatyp."))
|
|
cloudpath = cloudpath + '/' + str(Medium.cloudlink)
|
|
_logger.info("Copy file to Cloud Path : "+str(cloudpath))
|
|
try:
|
|
client = Client("https://cloud.logumedia.de/remote.php/dav/files/OdooDav/", auth=("odooClient@logumedia.de", "lm2020#OdooDav"))
|
|
try:
|
|
#client.mkdir(new_folder)
|
|
#_logger.info("Make Cloud Path : "+str(new_folder))
|
|
client.upload_file(filename, f"{cloudpath}/{filename}")
|
|
except Exception as e:
|
|
_logger.info("Make Cloud Path error : "+str(e))
|
|
finally:
|
|
self.binary_issaved = True
|
|
_logger.info("File copied to Cloud Path : "+str(cloudpath))
|
|
return True
|
|
|