Breaking up the code smell regarding the CFG.py!

It began smelling already but having some duplicate code across the
interfaces is still better than having all of it all over the place.

It enables to write specific flags which are nice to have. For example,
Import.py requires the --Import flag because it WANTS the user to read
the whole Help before it acts actually as an importer. When the user
supplies something they should know what's currently happening.

Also removes the hardcoded dependency on lib.CFG-Calls from most calls
which was already embarassingly present. Introduced some db and
cfg-variables which doesnt clutter anything but suck much less.

In future we provide a set of default arguments and a bare minimum -
config_ui as the bare minimum, default as the full blown storm.

This is rather big because it also patches several other smells
including a bug where a user from the db wouldnt be reported as existent
feature-admin-split
Darksider3 5 years ago
parent 934b6bf75a
commit 710ceacd7c

@ -26,13 +26,6 @@ ENV TILDE_CONF="/app/data/applicationsconfig.ini"
# private/{scripts, administrate.py}, public/{scripts, userapplications.py}, config/userapplicatonsconfig.ini
#configs, logs, db
COPY config/applicationsconfig.ini /app/data/applicationsconfig.ini
# admin scripts
COPY private/ /app/admin/
# user accessible scripts
# Make TILDE_ENV
COPY public/ /app/user/
#SSH config into /etc :)
COPY config/etc /etc
@ -41,5 +34,11 @@ RUN touch /app/data/applications.log
# Doesnt work, @TODO why
#RUN setfacl -R -m u:tilde:rwx /app/data/
RUN chown -R tilde /app/data
# admin scripts
COPY private/ /app/admin/
# user accessible scripts
# Make TILDE_ENV
COPY public/ /app/user/
RUN mkdir /app/user/.ssh
CMD ["sh", "-c", " echo TILDE_CONF=$TILDE_CONF > /app/user/.ssh/environment && exec /usr/sbin/sshd -D"]

@ -3,7 +3,14 @@
import ListUsers
import csv
import io
import lib.CFG
import configparser
import lib.uis.default as default_cmd # Follows -u, -a, -f flags
default_cmd.argparser.description += " - Backups Tilde Users to stdout or a file."
args = default_cmd.argparser.parse_args()
config = configparser.ConfigParser()
config.read(args.config)
class Backup:
@ -12,7 +19,7 @@ class Backup:
dialect: str
field_names: tuple
def __init__(self, fname: str = lib.CFG.args.file, quoting: int = csv.QUOTE_NONNUMERIC, dialect: str = "excel"):
def __init__(self, fname: str, quoting: int = csv.QUOTE_NONNUMERIC, dialect: str = "excel"):
self.setFilename(fname)
self.setQuoting(quoting)
self.setDialect(dialect)
@ -46,13 +53,10 @@ class Backup:
if __name__ == "__main__":
try:
L = ListUsers.ListUsers()
L = ListUsers.ListUsers(config['DEFAULT']['applications_db'], uap=args.unapproved, app=args.approved)
fetch = L.getFetch()
B = Backup()
if lib.CFG.args.Import:
print("For importing please call the ./Import.py file with the --Import flag")
else:
B.BackupToFile(fetch)
B = Backup(args.file)
B.BackupToFile(fetch)
exit(0)
except KeyboardInterrupt as e:
pass

@ -1,11 +1,21 @@
import lib.CFG
import csv
import os
import configparser
import lib.UserExceptions
import lib.uis.config_ui # dont go to default, just following -c flag
ArgParser = lib.uis.config_ui.argparser
ArgParser.description += "- Imports a CSV file consisting of user specific details to the database"
ArgParser.add_argument('-f', '--file', default="stdout",
type=str, help='Import from CSV file', required=True)
ArgParser.add_argument('--Import', default=False, action="store_true",
help="Import Users.", required=True)
args = ArgParser.parse_args()
config = configparser.ConfigParser()
config.read(args.config)
def ImportFromFile(fname: str = lib.CFG.args.file, db: str = lib.CFG.config['DEFAULT']['applications_db'],
userids: tuple = tuple([])):
def ImportFromFile(fname: str, db: str, userids: tuple = tuple([])):
if not os.path.isfile(fname):
print(f"File {fname} don't exist")
return None
@ -18,14 +28,14 @@ def ImportFromFile(fname: str = lib.CFG.args.file, db: str = lib.CFG.config['DEF
try:
with open(fname, 'r', newline='') as f:
import lib.validator
err = lib.validator.checkImportFile(f)
sql = lib.sqlitedb.SQLitedb(db)
err = lib.validator.checkImportFile(fname, db)
if err is not True:
print(err)
exit(0)
import lib.sqlitedb
import lib.System
sysctl = lib.System.System()
sql = lib.sqlitedb.SQLitedb(lib.CFG.config['DEFAULT']['applications_db'])
reader = csv.DictReader(f) # @TODO csv.Sniffer to compare? When yes, give force-accept option
for row in reader:
if row["status"] == "1":
@ -64,14 +74,14 @@ def ImportFromFile(fname: str = lib.CFG.args.file, db: str = lib.CFG.config['DEF
if __name__ == "__main__":
try:
if not lib.CFG.args.Import:
if not args.Import:
print("Error, need the import flag")
if not lib.CFG.args.file:
if not args.file:
print("Error, need the import file")
if not lib.CFG.args.file:
if not args.file:
print("You MUST set a CSV-file with the -f/--file flag that already exist")
exit(1)
ImportFromFile()
ImportFromFile(args.file, config['DEFAULT']['applications_db'])
exit(0)
except KeyboardInterrupt as e:
pass

@ -1,15 +1,21 @@
#!/usr/bin/env python3
from lib.sqlitedb import SQLitedb
import lib.CFG
import configparser
import lib.uis.default as default_cmd # Follows -u, -a, -f flags
default_cmd.argparser.description += " - Lists Users from the Tilde database."
args = default_cmd.argparser.parse_args()
config = configparser.ConfigParser()
config.read(args.config)
class ListUsers:
db = None
usersFetch = None
def __init__(self, uap: bool = lib.CFG.args.unapproved, app: bool = lib.CFG.args.approved):
self.db = SQLitedb(lib.CFG.config['DEFAULT']['applications_db'])
def __init__(self, db: str, uap: bool = False, app: bool = True):
self.db = SQLitedb(db)
if uap: # only unapproved users
query = "SELECT * FROM `applications` WHERE status = '0'"
elif app: # Approved users
@ -33,7 +39,7 @@ class ListUsers:
if __name__ == "__main__":
try:
ret = ""
L = ListUsers()
L = ListUsers(config['DEFAULT']['applications_db'], uap=args.unapproved, app=args.approved)
fetch = L.getFetch()
# @TODO MAYBE best solution: https://pypi.org/project/texttable/
# examle:
@ -64,8 +70,8 @@ print(t.draw())
ret += "%-4i| %-14s| %-25s| %-22s| %-8s | %-5i |\n" % (
user["id"], user["username"], user["email"], user["name"], user["timestamp"], user["status"]
)
if lib.CFG.args.file != "stdout":
with open(lib.CFG.args.file, 'w') as f:
if args.file != "stdout":
with open(args.file, 'w') as f:
print(ret, file=f)
else:
print(ret)

@ -0,0 +1,7 @@
import lib.uis.default
argparser = lib.uis.default.argparser
args = argparser.parse_args()
config = argparser.ConfigParser()
config.read(args.config)

@ -44,4 +44,3 @@ class UsernameTooLong(User):
class UsernameInvalidCharacters(User):
pass

@ -1,6 +1,6 @@
import argparse
import lib.cwd
argparser = argparse.ArgumentParser(description='Tilde administration tools')
argparser = argparse.ArgumentParser(description='Tilde administration tools ', conflict_handler="resolve")
argparser.add_argument('-c', '--config', default=lib.cwd.cwd,
type=str, help='Path to configuration file', required=False)

@ -9,8 +9,3 @@ argparser.add_argument('-a', '--approved', default=False, action="store_true",
help="Only approved Users.", required=False)
argparser.add_argument('-f', '--file', default="stdout",
type=str, help='write to file instead of stdout', required=False)
argparser.add_argument('--Import', default=False, action="store_true",
help="Import Users from file. Affects currently only Import.py.\n"
"Setting this to true will result in -f being interpreted as the input file to import "
"users from. The file MUST be a comma separated CSV file being readable having it's "
"defined columns written in the first line.")

@ -1,7 +1,6 @@
import re
import pwd
import lib.sqlitedb
import lib.CFG
def checkUsernameCharacters(username: str):
@ -21,20 +20,18 @@ def checkUsernameLength(username: str):
return True
def checkUserExists(username: str):
def checkUserExists(username: str, db: str):
try:
pwd.getpwnam(username)
except KeyError:
return True # User already exists
else:
if checkUserInDB(username):
return True
return False
def checkUserInDB(username: str):
def checkUserInDB(username: str, db: str):
try:
ldb = lib.sqlitedb.SQLitedb(lib.CFG.config['DEFAULT']['applications_db'])
ldb = lib.sqlitedb.SQLitedb(db)
fetched = ldb.safequery("SELECT * FROM 'applications' WHERE username = ?", tuple([username]))
if fetched:
return True
@ -78,39 +75,39 @@ def checkDatetimeFormat(form: str):
return True
def checkImportFile(f):
import csv
reador = csv.DictReader(f)
def checkImportFile(fname: str, db: str):
error_list = str()
valid = True
ln = 1 # line number
for row in reador:
# if any of this fails move on to the next user, just print a relatively helpful message lel
if not lib.validator.checkUsernameCharacters(row["username"]):
error_list += (f"Line {ln}: Username contains unsupported characters or starts with a number: '"
f"{row['username']}'.\n")
valid = False
if not lib.validator.checkUsernameLength(row["username"]):
error_list += f"Line {ln}: Username '{row['username']}' is either too long(>16) or short(<3)\n"
valid = False
if not lib.validator.checkSSHKey(row["pubkey"]):
error_list += f"Line {ln}: Following SSH-Key of user '{row['username']}' isn't valid: '{row['pubkey']}'."\
f"\n"
valid = False
if not lib.validator.checkEmail(row["email"]):
error_list += f"Line {ln}: E-Mail address of user '{row['username']}' '{row['email']}' is not valid.\n"
valid = False
if not lib.validator.checkUserExists(row["username"]):
error_list += f"Line {ln}: User '{row['username']}' already exists.\n"
valid = False
if not lib.validator.checkDatetimeFormat(row["timestamp"]):
error_list += f"Line {ln}: Timestamp '{row['timestamp']}' from user '{row['username']}' is invalid.\n"
valid = False
if int(row["status"]) > 1 or int(row["status"]) < 0:
error_list += f"Line {ln}: Status '{row['status']}' MUST be either 0 or 1.\n"
valid = False
ln += 1
with open(fname, 'r', newline='') as f:
import csv
reador = csv.DictReader(f)
for row in reador:
# if any of this fails move on to the next user, just print a relatively helpful message lel
if not lib.validator.checkUsernameCharacters(row["username"]):
error_list += (f"Line {ln}: Username contains unsupported characters or starts with a number: '"
f"{row['username']}'.\n")
valid = False
if not lib.validator.checkUsernameLength(row["username"]):
error_list += f"Line {ln}: Username '{row['username']}' is either too long(>16) or short(<3)\n"
valid = False
if not lib.validator.checkSSHKey(row["pubkey"]):
error_list += f"Line {ln}: Following SSH-Key of user '{row['username']}' isn't valid: '{row['pubkey']}'."\
f"\n"
valid = False
if not lib.validator.checkEmail(row["email"]):
error_list += f"Line {ln}: E-Mail address of user '{row['username']}' '{row['email']}' is not valid.\n"
valid = False
if not lib.validator.checkUserExists(row["username"], db) or checkUserInDB(row["username"], db):
error_list += f"Line {ln}: User '{row['username']}' already exists.\n"
valid = False
if not lib.validator.checkDatetimeFormat(row["timestamp"]):
error_list += f"Line {ln}: Timestamp '{row['timestamp']}' from user '{row['username']}' is invalid.\n"
valid = False
if int(row["status"]) > 1 or int(row["status"]) < 0:
error_list += f"Line {ln}: Status '{row['status']}' MUST be either 0 or 1.\n"
valid = False
ln += 1
if valid:
return True
else:

Loading…
Cancel
Save