resolve conflict

This commit is contained in:
Cayo Puigdefabregas 2023-03-15 15:49:35 +01:00
commit 174928872f
10 changed files with 186 additions and 104 deletions

View File

@ -132,7 +132,10 @@ class SanitizationEntityForm(FlaskForm):
logo = URLField( logo = URLField(
'Logo', 'Logo',
[validators.Optional(), validators.URL()], [validators.Optional(), validators.URL()],
render_kw={'class': "form-control"}, render_kw={
'class': "form-control",
"placeholder": "Url where is the logo - acceptd only .png, .jpg, .gif, svg",
},
) )
company_name = StringField('Company Name', render_kw={'class': "form-control"}) company_name = StringField('Company Name', render_kw={'class': "form-control"})
location = StringField('Location', render_kw={'class': "form-control"}) location = StringField('Location', render_kw={'class': "form-control"})
@ -154,18 +157,29 @@ class SanitizationEntityForm(FlaskForm):
if not is_valid: if not is_valid:
return False return False
if not self.logo.data:
return True
extensions = ["jpg", "jpeg", "png", "gif", "svg"]
if self.logo.data.lower().split(".")[-1] not in extensions:
txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions"
self.logo.errors = [txt]
return False
return True return True
def save(self, commit=True): def save(self, commit=True):
sanitation_data = SanitizationEntity( if isinstance(self.logo.data, str):
logo=URL(self.logo.data), self.logo.data = URL(self.logo.data)
company_name=self.company_name.data,
location=self.location.data, sanitation_data = SanitizationEntity.query.filter_by(user_id=g.user.id).first()
responsable_person=self.responsable_person.data,
supervisor_person=self.supervisor_person.data, if not sanitation_data:
user=g.user, sanitation_data = SanitizationEntity(user_id=g.user.id)
) self.populate_obj(sanitation_data)
db.session.add(sanitation_data) db.session.add(sanitation_data)
else:
self.populate_obj(sanitation_data)
if commit: if commit:
db.session.commit() db.session.commit()

View File

@ -1540,7 +1540,10 @@ class CustomerDetailsForm(FlaskForm):
logo = URLField( logo = URLField(
'Logo', 'Logo',
[validators.Optional()], [validators.Optional()],
render_kw={'class': "form-control"}, render_kw={
'class': "form-control",
"placeholder": "Url where is the logo - acceptd only .png, .jpg, .gif, svg",
},
description="Url where is the logo", description="Url where is the logo",
) )
@ -1559,7 +1562,20 @@ class CustomerDetailsForm(FlaskForm):
def validate(self, extra_validators=None): def validate(self, extra_validators=None):
is_valid = super().validate(extra_validators) is_valid = super().validate(extra_validators)
return is_valid
if not is_valid:
return is_valid
if not self.logo.data:
return True
extensions = ["jpg", "jpeg", "png", "gif", "svg"]
if self.logo.data.lower().split(".")[-1] not in extensions:
txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions"
self.logo.errors = [txt]
return False
return True
def save(self, commit=True): def save(self, commit=True):
self.populate_obj(self._obj) self.populate_obj(self._obj)

View File

@ -841,6 +841,21 @@ class NewTransferView(GenericMixin):
return flask.render_template(self.template_name, **self.context) return flask.render_template(self.template_name, **self.context)
class OpenTransferView(GenericMixin):
methods = ['GET']
def dispatch_request(self, lot_id=None):
lot = Lot.query.filter_by(id=lot_id).one()
next_url = url_for('inventory.lotdevicelist', lot_id=str(lot_id))
if hasattr(lot, 'transfer'):
lot.transfer.date = None
db.session.commit()
messages.success('Transfer was reopen successfully!')
return flask.redirect(next_url)
class EditTransferView(GenericMixin): class EditTransferView(GenericMixin):
methods = ['POST'] methods = ['POST']
form_class = EditTransferForm form_class = EditTransferForm
@ -1058,22 +1073,45 @@ class ExportsView(View):
erasures.append(device.privacy) erasures.append(device.privacy)
return erasures return erasures
def get_costum_details(self): def get_costum_details(self, erasures):
my_data = None my_data = None
customer_details = None customer_details = None
if hasattr(g.user, 'sanitization_entity'): lot = None
if g.user.sanitization_entity:
my_data = list(g.user.sanitization_entity)[0]
if hasattr(g.user, 'sanitization_entity'):
my_data = g.user.sanitization_entity
customer_details = self.get_customer_details_from_request()
if not erasures or customer_details:
return my_data, customer_details
lots = {erasures[0].device.get_last_incoming_lot()}
for e in erasures[1:]:
lots.add(e.device.get_last_incoming_lot())
if len(lots) != 1:
return my_data, customer_details
lot = lots.pop()
try: try:
if len(request.referrer.split('/lot/')) > 1: customer_details = lot.transfer.customer_details
lot_id = request.referrer.split('/lot/')[-1].split('/')[0]
lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first()
customer_details = lot.transfer.customer_details
except Exception: except Exception:
pass pass
return my_data, customer_details return my_data, customer_details
def get_customer_details_from_request(self):
try:
if len(request.referrer.split('/lot/')) < 2:
return
lot_id = request.referrer.split('/lot/')[-1].split('/')[0]
lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first()
return lot.transfer.customer_details
except Exception:
pass
def get_server_erasure_hosts(self, erasures): def get_server_erasure_hosts(self, erasures):
erasures_host = [] erasures_host = []
erasures_on_server = [] erasures_on_server = []
@ -1094,15 +1132,22 @@ class ExportsView(View):
erasures[0].snapshot.version, erasures[0].snapshot.version,
) )
my_data, customer_details = self.get_costum_details() my_data, customer_details = self.get_costum_details(erasures)
a, b = self.get_server_erasure_hosts(erasures) a, b = self.get_server_erasure_hosts(erasures)
erasures_host, erasures_on_server = a, b erasures_host, erasures_on_server = a, b
erasures_host = set(erasures_host)
result = 'Success' result = 'Success'
if "Failed" in [e.severity.get_public_name() for e in erasures]: if "Failed" in [e.severity.get_public_name() for e in erasures]:
result = 'Failed' result = 'Failed'
erasures = sorted(erasures, key=lambda x: x.end_time)
erasures_on_server = sorted(erasures_on_server, key=lambda x: x.end_time)
erasures_normal = list(set(erasures) - set(erasures_on_server))
erasures_normal = sorted(erasures_normal, key=lambda x: x.end_time)
n_computers = len({x.parent for x in erasures} - erasures_host)
params = { params = {
'title': 'Erasure Certificate', 'title': 'Erasure Certificate',
'erasures': tuple(erasures), 'erasures': tuple(erasures),
@ -1111,11 +1156,11 @@ class ExportsView(View):
'uuid_report': '{}'.format(uuid.uuid4()), 'uuid_report': '{}'.format(uuid.uuid4()),
'software': software, 'software': software,
'my_data': my_data, 'my_data': my_data,
'n_computers': len(set([x.parent for x in erasures])), 'n_computers': n_computers,
'result': result, 'result': result,
'customer_details': customer_details, 'customer_details': customer_details,
'erasure_hosts': erasures_host, 'erasure_hosts': erasures_host,
'erasures_normal': list(set(erasures) - set(erasures_on_server)), 'erasures_normal': erasures_normal,
} }
return flask.render_template('inventory/erasure.html', **params) return flask.render_template('inventory/erasure.html', **params)
@ -1571,3 +1616,7 @@ devices.add_url_rule(
'/device/erasure/<int:orphans>/', '/device/erasure/<int:orphans>/',
view_func=ErasureListView.as_view('device_erasure_list_orphans'), view_func=ErasureListView.as_view('device_erasure_list_orphans'),
) )
devices.add_url_rule(
'/lot/<string:lot_id>/opentransfer/',
view_func=OpenTransferView.as_view('open_transfer'),
)

View File

@ -678,6 +678,12 @@ class Device(Thing):
return args return args
def get_lots_for_template(self): def get_lots_for_template(self):
if self.binding:
return self.binding.device.get_lots_for_template()
if not self.lots and hasattr(self, 'parent') and self.parent:
return self.parent.get_lots_for_template()
lots = [] lots = []
for lot in self.lots: for lot in self.lots:
if lot.is_incoming: if lot.is_incoming:
@ -1056,6 +1062,25 @@ class Device(Thing):
return return
def get_last_incoming_lot(self):
lots = list(self.lots)
if hasattr(self, "orphan") and self.orphan:
lots = list(self.lots)
if self.binding:
lots = list(self.binding.device.lots)
elif hasattr(self, "parent") and self.parent:
lots = list(self.parent.lots)
if self.parent.binding:
lots = list(self.parent.binding.device.lots)
lots = sorted(lots, key=lambda x: x.created)
lots.reverse()
for lot in lots:
if lot.is_incoming:
return lot
return None
def __lt__(self, other): def __lt__(self, other):
return self.id < other.id return self.id < other.id

View File

@ -3,12 +3,12 @@ from uuid import uuid4
from citext import CIText from citext import CIText
from flask import current_app as app from flask import current_app as app
from flask import session from flask import g, session
from flask_login import UserMixin from flask_login import UserMixin
from sqlalchemy import BigInteger, Boolean, Column, Sequence from sqlalchemy import BigInteger, Boolean, Column, Sequence
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy_utils import EmailType, PasswordType from sqlalchemy_utils import EmailType, PasswordType
from teal.db import URL, IntEnum from teal.db import CASCADE_OWN, URL, IntEnum
from ereuse_devicehub.db import db from ereuse_devicehub.db import db
from ereuse_devicehub.resources.enums import SessionType from ereuse_devicehub.resources.enums import SessionType
@ -181,18 +181,24 @@ class Session(Thing):
class SanitizationEntity(Thing): class SanitizationEntity(Thing):
id = Column(BigInteger, primary_key=True) id = db.Column(BigInteger, primary_key=True)
company_name = Column(db.String, nullable=True) company_name = db.Column(db.String, nullable=True)
location = Column(db.String, nullable=True) location = db.Column(db.String, nullable=True)
logo = Column(db.String, nullable=True) # logo = db.Column(db.String, nullable=True)
logo = Column(URL(), nullable=True) logo = db.Column(URL(), nullable=True)
responsable_person = Column(db.String, nullable=True) responsable_person = db.Column(db.String, nullable=True)
supervisor_person = Column(db.String, nullable=True) supervisor_person = db.Column(db.String, nullable=True)
user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) user_id = db.Column(
db.UUID(as_uuid=True),
db.ForeignKey(User.id),
default=lambda: g.user.id,
)
user = db.relationship( user = db.relationship(
User, User,
backref=db.backref('sanitization_entity', lazy=True, collection_class=set), backref=db.backref(
collection_class=set, 'sanitization_entity', lazy=True, uselist=False, cascade=CASCADE_OWN
),
primaryjoin=user_id == User.id,
) )
def __str__(self) -> str: def __str__(self) -> str:

View File

@ -516,13 +516,13 @@
</div> </div>
{% if lot and not lot.is_temporary %} {% if lot and not lot.is_temporary %}
<div id="trade-documents-list" class="tab-pane fade trade-documents-list"> <div id="trade-documents-list" class="tab-pane fade trade-documents-list">
<div class="btn-group dropdown ml-1 mt-1" uib-dropdown=""> <div class="btn-group dropdown ml-1 mt-1" uib-dropdown="">
<a href="{{ url_for('inventory.trade_document_add', lot_id=lot.id)}}" class="btn btn-primary"> <a href="{{ url_for('inventory.trade_document_add', lot_id=lot.id)}}" class="btn btn-primary">
<i class="bi bi-plus"></i> <i class="bi bi-plus"></i>
Add new document Add new document
<span class="caret"></span> <span class="caret"></span>
</a> </a>
</div> </div>
<h5 class="card-title">Documents</h5> <h5 class="card-title">Documents</h5>
<table class="table"> <table class="table">
@ -565,6 +565,15 @@
</table> </table>
</div> </div>
<div id="edit-transfer" class="tab-pane fade edit-transfer"> <div id="edit-transfer" class="tab-pane fade edit-transfer">
{% if form_transfer.date.data %}
<div class="btn-group dropdown ml-1 mt-1" uib-dropdown="">
<a href="{{ url_for('inventory.open_transfer', lot_id=lot.id)}}" class="btn btn-primary">
<i class="bi bi-plus"></i>
Reopen a transfer
<span class="caret"></span>
</a>
</div>
{% endif %}
<h5 class="card-title">Transfer</h5> <h5 class="card-title">Transfer</h5>
<form method="post" action="{{ url_for('inventory.edit_transfer', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate> <form method="post" action="{{ url_for('inventory.edit_transfer', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
{{ form_transfer.csrf_token }} {{ form_transfer.csrf_token }}

View File

@ -159,19 +159,20 @@
<table class="body_content"> <table class="body_content">
<tbody> <tbody>
{% if erasure_hosts %} {% if erasure_hosts %}
{% for e in erasure_hosts %}
<tr style="padding-top:5px;"> <tr style="padding-top:5px;">
<td style="width:20%;"> <td style="width:20%;">
<span>N&deg; of sanitization server ({{ loop.index }}/{{ erasure_hosts|length }}):</span> <span>SNs of sanitization server:</span>
</td> </td>
<td style="width:80%;"> <td style="width:80%;">
{% for e in erasure_hosts %}
{% if e.serial_number %} {% if e.serial_number %}
<span>{{ e.serial_number.upper() }}</span> <span>{{ e.serial_number.upper() }}</span>{% if not loop.last %},{% endif %}
{% endif %} {% endif %}
{% endfor %}
</td> </td>
</tr> </tr>
{% endfor %} {% endif %}
{% else %} {% if n_computers %}
<tr style="padding-top:5px;"> <tr style="padding-top:5px;">
<td style="width:20%;"> <td style="width:20%;">
<span>N&deg; of computers:</span> <span>N&deg; of computers:</span>
@ -245,7 +246,7 @@
</div> </div>
</div> </div>
<div class="row" style="margin-top:225px;"> <div class="row" style="margin-top:200px;">
<div class="col-12"> <div class="col-12">
<table class="body_content" style="border-top: 1px solid #000;"> <table class="body_content" style="border-top: 1px solid #000;">
<tbody> <tbody>
@ -266,14 +267,9 @@
</div> </div>
{% if erasures %} {% if erasures %}
{% if erasure_hosts %}
{% for server in erasure_hosts %}
<div class="row mt-3 page-break"> <div class="row mt-3 page-break">
<div class="col"> <div class="col">
<h1>Server Summary</h1> <h1>Summary</h1>
</div>
<div class="col">
<h4>SN Server {{ server.serial_number and server.serial_number.upper() }}</h4>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
@ -282,6 +278,7 @@
<thead style="border-bottom: 1px solid #000;"> <thead style="border-bottom: 1px solid #000;">
<tr> <tr>
<th scope="col" style="text-align: center;">SN Storage</th> <th scope="col" style="text-align: center;">SN Storage</th>
<th scope="col" style="text-align: center;">SN Host</th>
<th scope="col" style="text-align: center;">Method</th> <th scope="col" style="text-align: center;">Method</th>
<th scope="col" style="text-align: center;">Result</th> <th scope="col" style="text-align: center;">Result</th>
<th scope="col" style="text-align: center;">Date</th> <th scope="col" style="text-align: center;">Date</th>
@ -289,51 +286,12 @@
</thead> </thead>
<tbody> <tbody>
{% for erasure in erasures %} {% for erasure in erasures %}
{% if erasure.parent == server %}
<tr style="border-bottom: 1px dashed #000;"> <tr style="border-bottom: 1px dashed #000;">
<td> <td>
{{ erasure.device.serial_number.upper() }} {{ erasure.device.serial_number.upper() }}
</td> </td>
<td> <td>
{{ erasure.get_public_name() }} {{ erasure.parent.serial_number.upper() }}
</td>
<td>
{{ erasure.severity.get_public_name() }}
</td>
<td>
{{ erasure.date_str }}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
{% endif %}
{% if erasures_normal %}
<div class="row mt-3 page-break">
<div class="col">
<h1>Devices Summary</h1>
</div>
</div>
<div class="row mt-3">
<div class="col">
<table class="table" style="width: 100%; text-align: center;">
<thead style="border-bottom: 1px solid #000;">
<tr>
<th scope="col" style="text-align: center;">SN Storage</th>
<th scope="col" style="text-align: center;">Method</th>
<th scope="col" style="text-align: center;">Result</th>
<th scope="col" style="text-align: center;">Date</th>
</tr>
</thead>
<tbody>
{% for erasure in erasures_normal %}
<tr style="border-bottom: 1px dashed #000;">
<td>
{{ erasure.device.serial_number.upper() }}
</td> </td>
<td> <td>
{{ erasure.get_public_name() }} {{ erasure.get_public_name() }}
@ -350,7 +308,6 @@
</table> </table>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
{% for erasure in erasures %} {% for erasure in erasures %}
<div class="container mb-5 page-break"> <div class="container mb-5 page-break">
@ -366,12 +323,14 @@
<dd>Hid: {{ erasure.parent.hid }}</dd> <dd>Hid: {{ erasure.parent.hid }}</dd>
<dd>Tags: {{ erasure.parent.tags }}</dd> <dd>Tags: {{ erasure.parent.tags }}</dd>
{% if erasure.device.parent %}
<dt>Computer where it resides:</dt> <dt>Computer where it resides:</dt>
<dd>Title: {{ erasure.device.parent.__format__('ts') }}</dd> <dd>Title: {{ erasure.device.parent.__format__('ts') }}</dd>
<dd>DevicehubID: {{ erasure.device.parent.dhid }}</dd> <dd>DevicehubID: {{ erasure.device.parent.dhid }}</dd>
<dd>Hid: {{ erasure.device.parent.hid }}</dd> <dd>Hid: {{ erasure.device.parent.hid }}</dd>
<dd>Tags: {{ erasure.device.parent.tags }}</dd> <dd>Tags: {{ erasure.device.parent.tags }}</dd>
{% endif %} {% endif %}
{% endif %}
<dt>Erasure:</dt> <dt>Erasure:</dt>
<dd>{{ erasure.__format__('ts') }}</dd> <dd>{{ erasure.__format__('ts') }}</dd>

View File

@ -187,9 +187,9 @@
{% endif %} {% endif %}
{{ ac.device.serial_number.upper() }} {{ ac.device.serial_number.upper() }}
{% endif %} {% endif %}
{% if ac.device.my_partner.lots | length > 0 %} {% if ac.device.get_lots_for_template() | length > 0 %}
<h6 class="d-inline"> <h6 class="d-inline">
{% for lot in ac.device.my_partner.get_lots_for_template() %} {% for lot in ac.device.get_lots_for_template() %}
<span class="badge rounded-pill bg-light text-dark">{{ lot }}</span> <span class="badge rounded-pill bg-light text-dark">{{ lot }}</span>
{% endfor %} {% endfor %}
</h6> </h6>

View File

@ -102,7 +102,7 @@ class UserProfileView(GenericMixin):
self.get_context() self.get_context()
sanitization_form = SanitizationEntityForm() sanitization_form = SanitizationEntityForm()
if g.user.sanitization_entity: if g.user.sanitization_entity:
sanitization = list(g.user.sanitization_entity)[0] sanitization = g.user.sanitization_entity
sanitization_form = SanitizationEntityForm(obj=sanitization) sanitization_form = SanitizationEntityForm(obj=sanitization)
self.context.update( self.context.update(
{ {
@ -138,14 +138,17 @@ class SanitizationEntityView(View):
def dispatch_request(self): def dispatch_request(self):
form = SanitizationEntityForm() form = SanitizationEntityForm()
db.session.commit()
if form.validate_on_submit(): if form.validate_on_submit():
form.save(commit=False) form.save()
messages.success('Sanitization datas updated successfully!') messages.success('Sanitization data updated successfully!')
else: else:
messages.error('Error modifying Sanitization datas!') messages.error('Error modifying Sanitization data!')
if form.errors:
for k in form.errors.keys():
errors = ", ".join(form.errors[k])
txt = "{}: {}".format(k, errors)
messages.error(txt)
db.session.commit()
return flask.redirect(flask.url_for('core.user-profile')) return flask.redirect(flask.url_for('core.user-profile'))

View File

@ -68,6 +68,7 @@ def test_api_docs(client: Client):
'/inventory/lot/{lot_id}/receivernote/', '/inventory/lot/{lot_id}/receivernote/',
'/inventory/lot/{lot_id}/trade-document/add/', '/inventory/lot/{lot_id}/trade-document/add/',
'/inventory/lot/{lot_id}/transfer/{type_id}/', '/inventory/lot/{lot_id}/transfer/{type_id}/',
'/inventory/lot/{lot_id}/opentransfer/',
'/inventory/lot/{lot_id}/transfer/', '/inventory/lot/{lot_id}/transfer/',
'/inventory/lot/transfer/{type_id}/', '/inventory/lot/transfer/{type_id}/',
'/inventory/lot/{lot_id}/upload-snapshot/', '/inventory/lot/{lot_id}/upload-snapshot/',