Pre-fixing JSON update bug.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
- Various bug fixes.
|
- Various bug fixes.
|
||||||
- Move import PCR results to context menu.
|
- Move import PCR results to context menu.
|
||||||
|
- Automated backup of database.
|
||||||
- Added ability to sign off on submission in submission details.
|
- Added ability to sign off on submission in submission details.
|
||||||
|
|
||||||
## 202403.03
|
## 202403.03
|
||||||
|
|||||||
8
TODO.md
8
TODO.md
@@ -1,5 +1,11 @@
|
|||||||
|
- [ ] Appending of qPCR results to WW not saving. Find out why.
|
||||||
|
- Possibly due to immutable JSON? But... it's worked before... Right?
|
||||||
|
- Based on research, if a top-level JSON field is not changed, SQLalchemy will not detect changes.
|
||||||
|
- May have to use a special class: [link](https://docs.sqlalchemy.org/en/14/orm/extensions/mutable.html#establishing-mutability-on-scalar-column-values)
|
||||||
|
- [ ] Add Bead basher and Assit to DB.
|
||||||
|
- [x] Artic not creating right plate name.
|
||||||
- [ ] Merge BasicSubmission.find_subclasses and BasicSubmission.find_polymorphic_subclass
|
- [ ] Merge BasicSubmission.find_subclasses and BasicSubmission.find_polymorphic_subclass
|
||||||
- [ ] Fix updating of Extraction Kit in submission form widget.
|
- [x] Fix updating of Extraction Kit in submission form widget.
|
||||||
- [x] Fix cropping of gel image.
|
- [x] Fix cropping of gel image.
|
||||||
- [ ] Create Tips ... *sigh*.
|
- [ ] Create Tips ... *sigh*.
|
||||||
- [x] Create platemap image from html for export to pdf.
|
- [x] Create platemap image from html for export to pdf.
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class BaseClass(Base):
|
|||||||
"""
|
"""
|
||||||
Add the object to the database and commit
|
Add the object to the database and commit
|
||||||
"""
|
"""
|
||||||
|
logger.debug(f"Saving object: {pformat(self.__dict__)}")
|
||||||
try:
|
try:
|
||||||
self.__database_session__.add(self)
|
self.__database_session__.add(self)
|
||||||
self.__database_session__.commit()
|
self.__database_session__.commit()
|
||||||
|
|||||||
@@ -436,6 +436,7 @@ class BasicSubmission(BaseClass):
|
|||||||
Args:
|
Args:
|
||||||
original (bool, optional): Is this the first save. Defaults to True.
|
original (bool, optional): Is this the first save. Defaults to True.
|
||||||
"""
|
"""
|
||||||
|
logger.debug("Saving submission.")
|
||||||
if original:
|
if original:
|
||||||
self.uploaded_by = getuser()
|
self.uploaded_by = getuser()
|
||||||
super().save()
|
super().save()
|
||||||
@@ -605,12 +606,15 @@ class BasicSubmission(BaseClass):
|
|||||||
# logger.info(f"Hello from {cls.__mapper_args__['polymorphic_identity']} Enforcer!")
|
# logger.info(f"Hello from {cls.__mapper_args__['polymorphic_identity']} Enforcer!")
|
||||||
# return instr
|
# return instr
|
||||||
from backend.validators import RSLNamer
|
from backend.validators import RSLNamer
|
||||||
|
logger.debug(f"instr coming into {cls}: {instr}")
|
||||||
|
logger.debug(f"data coming into {cls}: {data}")
|
||||||
defaults = cls.get_default_info()
|
defaults = cls.get_default_info()
|
||||||
data['abbreviation'] = defaults['abbreviation']
|
data['abbreviation'] = defaults['abbreviation']
|
||||||
if 'submission_type' not in data.keys() or data['submission_type'] in [None, ""]:
|
if 'submission_type' not in data.keys() or data['submission_type'] in [None, ""]:
|
||||||
data['submission_type'] = defaults['submission_type']
|
data['submission_type'] = defaults['submission_type']
|
||||||
# outstr = super().enforce_name(instr=instr, data=data)
|
# outstr = super().enforce_name(instr=instr, data=data)
|
||||||
if instr in [None, ""]:
|
if instr in [None, ""]:
|
||||||
|
logger.debug("Sending to RSLNamer to make new plate name.")
|
||||||
outstr = RSLNamer.construct_new_plate_name(data=data)
|
outstr = RSLNamer.construct_new_plate_name(data=data)
|
||||||
else:
|
else:
|
||||||
outstr = instr
|
outstr = instr
|
||||||
@@ -620,6 +624,7 @@ class BasicSubmission(BaseClass):
|
|||||||
outstr = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\1\2\3", outstr)
|
outstr = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\1\2\3", outstr)
|
||||||
outstr = re.sub(rf"{data['abbreviation']}(\d{6})", rf"{data['abbreviation']}-\1", outstr, flags=re.IGNORECASE).upper()
|
outstr = re.sub(rf"{data['abbreviation']}(\d{6})", rf"{data['abbreviation']}-\1", outstr, flags=re.IGNORECASE).upper()
|
||||||
except (AttributeError, TypeError) as e:
|
except (AttributeError, TypeError) as e:
|
||||||
|
logger.error(f"Error making outstr: {e}, sending to RSLNamer to make new plate name.")
|
||||||
outstr = RSLNamer.construct_new_plate_name(data=data)
|
outstr = RSLNamer.construct_new_plate_name(data=data)
|
||||||
try:
|
try:
|
||||||
plate_number = re.search(r"(?:(-|_)\d)(?!\d)", outstr).group().strip("_").strip("-")
|
plate_number = re.search(r"(?:(-|_)\d)(?!\d)", outstr).group().strip("_").strip("-")
|
||||||
@@ -1281,28 +1286,32 @@ class Wastewater(BasicSubmission):
|
|||||||
if hasattr(self, 'pcr_info') and self.pcr_info != None:
|
if hasattr(self, 'pcr_info') and self.pcr_info != None:
|
||||||
# existing = json.loads(sub.pcr_info)
|
# existing = json.loads(sub.pcr_info)
|
||||||
existing = self.pcr_info
|
existing = self.pcr_info
|
||||||
|
logger.debug(f"Found existing pcr info: {pformat(self.pcr_info)}")
|
||||||
else:
|
else:
|
||||||
existing = None
|
existing = None
|
||||||
if existing != None:
|
if existing != None:
|
||||||
# update pcr_info
|
# update pcr_info
|
||||||
try:
|
try:
|
||||||
logger.debug(f"Updating {type(existing)}: {existing} with {type(parser.pcr)}: {parser.pcr}")
|
logger.debug(f"Updating {type(existing)}:\n {pformat(existing)} with {type(parser.pcr)}:\n {pformat(parser.pcr)}")
|
||||||
# if json.dumps(parser.pcr) not in sub.pcr_info:
|
# if json.dumps(parser.pcr) not in sub.pcr_info:
|
||||||
if parser.pcr not in self.pcr_info:
|
if parser.pcr not in self.pcr_info:
|
||||||
|
logger.debug(f"This is new pcr info, appending to existing")
|
||||||
existing.append(parser.pcr)
|
existing.append(parser.pcr)
|
||||||
logger.debug(f"Setting: {existing}")
|
else:
|
||||||
|
logger.debug("This info already exists, skipping.")
|
||||||
|
# logger.debug(f"Setting {self.rsl_plate_num} PCR to:\n {pformat(existing)}")
|
||||||
# sub.pcr_info = json.dumps(existing)
|
# sub.pcr_info = json.dumps(existing)
|
||||||
self.pcr_info = existing
|
self.pcr_info = existing
|
||||||
except TypeError:
|
except TypeError:
|
||||||
logger.error(f"Error updating!")
|
logger.error(f"Error updating!")
|
||||||
# sub.pcr_info = json.dumps([parser.pcr])
|
# sub.pcr_info = json.dumps([parser.pcr])
|
||||||
self.pcr_info = [parser.pcr]
|
self.pcr_info = [parser.pcr]
|
||||||
logger.debug(f"Final pcr info for {self.rsl_plate_num}: {self.pcr_info}")
|
logger.debug(f"Final pcr info for {self.rsl_plate_num}:\n {pformat(self.pcr_info)}")
|
||||||
else:
|
else:
|
||||||
# sub.pcr_info = json.dumps([parser.pcr])
|
# sub.pcr_info = json.dumps([parser.pcr])
|
||||||
self.pcr_info = [parser.pcr]
|
self.pcr_info = [parser.pcr]
|
||||||
logger.debug(f"Existing {type(self.pcr_info)}: {self.pcr_info}")
|
# logger.debug(f"Existing {type(self.pcr_info)}: {self.pcr_info}")
|
||||||
logger.debug(f"Inserting {type(parser.pcr)}: {parser.pcr}")
|
# logger.debug(f"Inserting {type(parser.pcr)}: {parser.pcr}")
|
||||||
self.save(original=False)
|
self.save(original=False)
|
||||||
logger.debug(f"Got {len(parser.samples)} samples to update!")
|
logger.debug(f"Got {len(parser.samples)} samples to update!")
|
||||||
logger.debug(f"Parser samples: {parser.samples}")
|
logger.debug(f"Parser samples: {parser.samples}")
|
||||||
@@ -1383,15 +1392,15 @@ class WastewaterArtic(BasicSubmission):
|
|||||||
instr = re.sub(r"Artic", "", instr, flags=re.IGNORECASE)
|
instr = re.sub(r"Artic", "", instr, flags=re.IGNORECASE)
|
||||||
except (AttributeError, TypeError) as e:
|
except (AttributeError, TypeError) as e:
|
||||||
logger.error(f"Problem using regex: {e}")
|
logger.error(f"Problem using regex: {e}")
|
||||||
try:
|
# try:
|
||||||
check = instr.startswith("RSL")
|
# check = instr.startswith("RSL")
|
||||||
except AttributeError:
|
# except AttributeError:
|
||||||
check = False
|
# check = False
|
||||||
if not check:
|
# if not check:
|
||||||
try:
|
# try:
|
||||||
instr = "RSL" + instr
|
# instr = "RSL" + instr
|
||||||
except:
|
# except TypeError:
|
||||||
instr = "RSL"
|
# instr = "RSL"
|
||||||
outstr = super().enforce_name(instr=instr, data=data)
|
outstr = super().enforce_name(instr=instr, data=data)
|
||||||
return outstr
|
return outstr
|
||||||
|
|
||||||
@@ -1540,7 +1549,8 @@ class WastewaterArtic(BasicSubmission):
|
|||||||
df.sort_values(by=['destination_column', 'destination_row'], inplace=True)
|
df.sort_values(by=['destination_column', 'destination_row'], inplace=True)
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
logger.error(f"Couldn't construct df due to {e}")
|
logger.error(f"Couldn't construct df due to {e}")
|
||||||
input_dict['csv'] = df
|
# input_dict['csv'] = df
|
||||||
|
input_dict['csv'] = xl.parse("hitpicks_csv_to_export")
|
||||||
return input_dict
|
return input_dict
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -266,7 +266,11 @@ class ReagentParser(object):
|
|||||||
# logger.debug(f"Got lot for {item}-{name}: {lot} as {type(lot)}")
|
# logger.debug(f"Got lot for {item}-{name}: {lot} as {type(lot)}")
|
||||||
lot = str(lot)
|
lot = str(lot)
|
||||||
logger.debug(f"Going into pydantic: name: {name}, lot: {lot}, expiry: {expiry}, type: {item.strip()}, comment: {comment}")
|
logger.debug(f"Going into pydantic: name: {name}, lot: {lot}, expiry: {expiry}, type: {item.strip()}, comment: {comment}")
|
||||||
if name.lower() != "not applicable":
|
try:
|
||||||
|
check = name.lower() != "not applicable"
|
||||||
|
except AttributeError:
|
||||||
|
check = True
|
||||||
|
if check:
|
||||||
listo.append(PydReagent(type=item.strip(), lot=lot, expiry=expiry, name=name, comment=comment, missing=missing))
|
listo.append(PydReagent(type=item.strip(), lot=lot, expiry=expiry, name=name, comment=comment, missing=missing))
|
||||||
return listo
|
return listo
|
||||||
|
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ class PydSample(BaseModel, extra='allow'):
|
|||||||
row=row, column=column, id=id)
|
row=row, column=column, id=id)
|
||||||
# logger.debug(f"Using submission_sample_association: {association}")
|
# logger.debug(f"Using submission_sample_association: {association}")
|
||||||
try:
|
try:
|
||||||
instance.sample_submission_associations.append(association)
|
# instance.sample_submission_associations.append(association)
|
||||||
out_associations.append(association)
|
out_associations.append(association)
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
logger.error(f"Could not attach submission sample association due to: {e}")
|
logger.error(f"Could not attach submission sample association due to: {e}")
|
||||||
@@ -809,7 +809,8 @@ class PydSubmission(BaseModel, extra='allow'):
|
|||||||
# # what reagent types are in both lists?
|
# # what reagent types are in both lists?
|
||||||
# missing = list(set(ext_kit_rtypes).difference(reagenttypes))
|
# missing = list(set(ext_kit_rtypes).difference(reagenttypes))
|
||||||
missing = []
|
missing = []
|
||||||
output_reagents = self.reagents
|
# output_reagents = self.reagents
|
||||||
|
output_reagents = ext_kit_rtypes
|
||||||
logger.debug(f"Already have these reagent types: {reagenttypes}")
|
logger.debug(f"Already have these reagent types: {reagenttypes}")
|
||||||
for rt in ext_kit_rtypes:
|
for rt in ext_kit_rtypes:
|
||||||
if rt.type not in reagenttypes:
|
if rt.type not in reagenttypes:
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ from PyQt6.QtWidgets import (
|
|||||||
from PyQt6.QtGui import QAction
|
from PyQt6.QtGui import QAction
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tools import check_if_app, Settings, Report
|
from tools import check_if_app, Settings, Report
|
||||||
|
from datetime import date
|
||||||
from .pop_ups import AlertPop
|
from .pop_ups import AlertPop
|
||||||
from .misc import LogParser
|
from .misc import LogParser
|
||||||
import logging, webbrowser, sys
|
import logging, webbrowser, sys, shutil
|
||||||
from .submission_table import SubmissionsSheet
|
from .submission_table import SubmissionsSheet
|
||||||
from .submission_widget import SubmissionFormContainer
|
from .submission_widget import SubmissionFormContainer
|
||||||
from .controls_chart import ControlsViewer
|
from .controls_chart import ControlsViewer
|
||||||
@@ -51,6 +52,7 @@ class App(QMainWindow):
|
|||||||
self._connectActions()
|
self._connectActions()
|
||||||
self.show()
|
self.show()
|
||||||
self.statusBar().showMessage('Ready', 5000)
|
self.statusBar().showMessage('Ready', 5000)
|
||||||
|
self.backup_database()
|
||||||
|
|
||||||
def _createMenuBar(self):
|
def _createMenuBar(self):
|
||||||
"""
|
"""
|
||||||
@@ -159,6 +161,16 @@ class App(QMainWindow):
|
|||||||
dlg = LogParser(self)
|
dlg = LogParser(self)
|
||||||
dlg.exec()
|
dlg.exec()
|
||||||
|
|
||||||
|
def backup_database(self):
|
||||||
|
month = date.today().strftime("%Y-%m")
|
||||||
|
# day = date.today().strftime("%Y-%m-%d")
|
||||||
|
logger.debug(f"Here is the db directory: {self.ctx.database_path}")
|
||||||
|
logger.debug(f"Here is the backup directory: {self.ctx.backup_path}")
|
||||||
|
current_month_bak = Path(self.ctx.backup_path).joinpath(f"submissions_backup-{month}").resolve().with_suffix(".db")
|
||||||
|
if not current_month_bak.exists() and "demo" not in self.ctx.database_path.__str__():
|
||||||
|
logger.debug("No backup found for this month, backing up database.")
|
||||||
|
shutil.copyfile(self.ctx.database_path, current_month_bak)
|
||||||
|
|
||||||
class AddSubForm(QWidget):
|
class AddSubForm(QWidget):
|
||||||
|
|
||||||
def __init__(self, parent:QWidget):
|
def __init__(self, parent:QWidget):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from PyQt6.QtWidgets import (
|
|||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from . import select_open_file, select_save_file
|
from . import select_open_file, select_save_file
|
||||||
import logging, difflib, inspect, json
|
import logging, difflib, inspect, pickle
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tools import Report, Result, check_not_nan
|
from tools import Report, Result, check_not_nan
|
||||||
from backend.excel.parser import SheetParser, PCRParser
|
from backend.excel.parser import SheetParser, PCRParser
|
||||||
@@ -147,7 +147,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
|
|
||||||
def __init__(self, parent: QWidget, submission:PydSubmission) -> None:
|
def __init__(self, parent: QWidget, submission:PydSubmission) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.report = Report()
|
# self.report = Report()
|
||||||
self.app = parent.app
|
self.app = parent.app
|
||||||
self.pyd = submission
|
self.pyd = submission
|
||||||
# self.input = [{k:v} for k,v in kwargs.items()]
|
# self.input = [{k:v} for k,v in kwargs.items()]
|
||||||
@@ -177,18 +177,18 @@ class SubmissionFormWidget(QWidget):
|
|||||||
self.scrape_reagents(self.pyd.extraction_kit)
|
self.scrape_reagents(self.pyd.extraction_kit)
|
||||||
# extraction kit must be added last so widget order makes sense.
|
# extraction kit must be added last so widget order makes sense.
|
||||||
# self.layout.addWidget(self.create_widget(key="extraction_kit", value=self.extraction_kit, submission_type=self.submission_type))
|
# self.layout.addWidget(self.create_widget(key="extraction_kit", value=self.extraction_kit, submission_type=self.submission_type))
|
||||||
if hasattr(self.pyd, "csv"):
|
# if hasattr(self.pyd, "csv"):
|
||||||
export_csv_btn = QPushButton("Export CSV")
|
# export_csv_btn = QPushButton("Export CSV")
|
||||||
export_csv_btn.setObjectName("export_csv_btn")
|
# export_csv_btn.setObjectName("export_csv_btn")
|
||||||
self.layout.addWidget(export_csv_btn)
|
# self.layout.addWidget(export_csv_btn)
|
||||||
export_csv_btn.clicked.connect(self.export_csv_function)
|
# export_csv_btn.clicked.connect(self.export_csv_function)
|
||||||
submit_btn = QPushButton("Submit")
|
# submit_btn = QPushButton("Submit")
|
||||||
submit_btn.setObjectName("submit_btn")
|
# submit_btn.setObjectName("submit_btn")
|
||||||
self.layout.addWidget(submit_btn)
|
# self.layout.addWidget(submit_btn)
|
||||||
submit_btn.clicked.connect(self.submit_new_sample_function)
|
# submit_btn.clicked.connect(self.submit_new_sample_function)
|
||||||
self.setLayout(self.layout)
|
# self.setLayout(self.layout)
|
||||||
self.app.report.add_result(self.report)
|
# self.app.report.add_result(self.report)
|
||||||
self.app.result_reporter()
|
# self.app.result_reporter()
|
||||||
|
|
||||||
def create_widget(self, key:str, value:dict|PydReagent, submission_type:str|None=None, extraction_kit:str|None=None) -> "self.InfoItem":
|
def create_widget(self, key:str, value:dict|PydReagent, submission_type:str|None=None, extraction_kit:str|None=None) -> "self.InfoItem":
|
||||||
"""
|
"""
|
||||||
@@ -230,7 +230,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
caller = inspect.stack()[1].function.__repr__().replace("'", "")
|
caller = inspect.stack()[1].function.__repr__().replace("'", "")
|
||||||
# self.reagents = []
|
# self.reagents = []
|
||||||
# logger.debug(f"Self.reagents: {self.reagents}")
|
# logger.debug(f"Self.reagents: {self.reagents}")
|
||||||
# logger.debug(f"\n\n{caller}\n\n")
|
logger.debug(f"\n\n{pformat(caller)}\n\n")
|
||||||
# logger.debug(f"SubmissionType: {self.submission_type}")
|
# logger.debug(f"SubmissionType: {self.submission_type}")
|
||||||
report = Report()
|
report = Report()
|
||||||
logger.debug(f"Extraction kit: {extraction_kit}")
|
logger.debug(f"Extraction kit: {extraction_kit}")
|
||||||
@@ -257,13 +257,25 @@ class SubmissionFormWidget(QWidget):
|
|||||||
# self.pyd.reagents = already_have + reagents
|
# self.pyd.reagents = already_have + reagents
|
||||||
# logger.debug(f"Reagents: {self.reagents}")
|
# logger.debug(f"Reagents: {self.reagents}")
|
||||||
# self.kit_integrity_completion_function(extraction_kit=extraction_kit)
|
# self.kit_integrity_completion_function(extraction_kit=extraction_kit)
|
||||||
reagents, report = self.pyd.check_kit_integrity(extraction_kit=extraction_kit)
|
reagents, integrity_report = self.pyd.check_kit_integrity(extraction_kit=extraction_kit)
|
||||||
# logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
# logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
||||||
for reagent in reagents:
|
for reagent in reagents:
|
||||||
add_widget = self.ReagentFormWidget(parent=self, reagent=reagent, extraction_kit=self.pyd.extraction_kit)
|
add_widget = self.ReagentFormWidget(parent=self, reagent=reagent, extraction_kit=self.pyd.extraction_kit)
|
||||||
self.layout.addWidget(add_widget)
|
self.layout.addWidget(add_widget)
|
||||||
self.report.add_result(report)
|
report.add_result(integrity_report)
|
||||||
logger.debug(f"Outgoing report: {self.report.results}")
|
logger.debug(f"Outgoing report: {report.results}")
|
||||||
|
if hasattr(self.pyd, "csv"):
|
||||||
|
export_csv_btn = QPushButton("Export CSV")
|
||||||
|
export_csv_btn.setObjectName("export_csv_btn")
|
||||||
|
self.layout.addWidget(export_csv_btn)
|
||||||
|
export_csv_btn.clicked.connect(self.export_csv_function)
|
||||||
|
submit_btn = QPushButton("Submit")
|
||||||
|
submit_btn.setObjectName("submit_btn")
|
||||||
|
self.layout.addWidget(submit_btn)
|
||||||
|
submit_btn.clicked.connect(self.submit_new_sample_function)
|
||||||
|
self.setLayout(self.layout)
|
||||||
|
self.app.report.add_result(report)
|
||||||
|
self.app.result_reporter()
|
||||||
|
|
||||||
def kit_integrity_completion_function(self, extraction_kit:str|None=None):
|
def kit_integrity_completion_function(self, extraction_kit:str|None=None):
|
||||||
"""
|
"""
|
||||||
@@ -302,7 +314,6 @@ class SubmissionFormWidget(QWidget):
|
|||||||
Alternatively, you may have set the wrong extraction kit.\n\nThe program will populate lists using existing reagents.
|
Alternatively, you may have set the wrong extraction kit.\n\nThe program will populate lists using existing reagents.
|
||||||
\n\nPlease make sure you check the lots carefully!""".replace(" ", ""), status="Warning")
|
\n\nPlease make sure you check the lots carefully!""".replace(" ", ""), status="Warning")
|
||||||
report.add_result(result)
|
report.add_result(result)
|
||||||
|
|
||||||
self.report.add_result(report)
|
self.report.add_result(report)
|
||||||
logger.debug(f"Outgoing report: {self.report.results}")
|
logger.debug(f"Outgoing report: {self.report.results}")
|
||||||
|
|
||||||
|
|||||||
@@ -538,7 +538,11 @@ def rreplace(s, old, new):
|
|||||||
ctx = get_config(None)
|
ctx = get_config(None)
|
||||||
|
|
||||||
def is_power_user() -> bool:
|
def is_power_user() -> bool:
|
||||||
return getpass.getuser() in ctx.power_users
|
try:
|
||||||
|
check = getpass.getuser() in ctx.power_users
|
||||||
|
except:
|
||||||
|
check = False
|
||||||
|
return check
|
||||||
|
|
||||||
def check_authorization(func):
|
def check_authorization(func):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user