DigitalSignage/models/dss_csvs.py

327 lines
17 KiB
Python
Executable File

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 dsscsvs(models.Model):
@api.model
def create(self,vals):
result = super().create(vals)
return result
_name = "dss.csvs"
_description = "DigitalSignage CSV Dateien"
# _inherit = ['mail.thread','mail.activity.mixin']
_rec_name = "csv_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')
csv_id = fields.Char(string="CSV 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_csv_id())
csv_name = fields.Char(string="CSV Name", required=True, help = "Der Name des Dateityp, die Sie hochladen möchten. Dieser Name wird in der Benutzeroberfläche angezeigt.")
csv_binary = fields.Binary(string="CSV Datei", help = "Die eigentliche Datei, die Sie hochladen möchten. Diese Datei wird in der Datenbank und Cloud gespeichert")
csv_filename = fields.Char(string="CSV Dateiname", help = "Der Name der hochgeladenen Datei. Dies wird automatisch aus dem Dateinamen der hochgeladenen Datei abgerufen.",compute="_compute_csv_filename", store=True)
csv_cloud_link = fields.Char(string="Cloud Link", help = "Der Link zur Datei in der Cloud, wenn die Datei in der Cloud gespeichert ist.")
csv_description = fields.Text(string="CSV Beschreibung", help = "Eine Beschreibung der hochgeladenen Datei. Dies kann Informationen über den Inhalt der Datei, den Verwendungszweck oder andere relevante Details enthalten.")
csv_attachment_id = fields.Many2one('ir.attachment', string="CSV Anhang", help = "Der Anhang, der mit dieser CSV-Datei verbunden ist. Dieser Anhang enthält die tatsächliche Datei, die in der Datenbank gespeichert ist.")
csv_mailtext = fields.Text(string="CSV Mailtext", help = "Der Text, der in der E-Mail verwendet wird, wenn diese CSV-Datei per E-Mail versendet wird.")
@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