viewo-helpdesk 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ #==============================================================================
2
+ # C O P Y R I G H T
3
+ #------------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ #==============================================================================
9
+
10
+ import importlib.metadata
11
+ import os
12
+
13
+ import utilo
14
+
15
+ import viewo_helpdesk.__patch__
16
+ from viewo_helpdesk.api import api_call
17
+ from viewo_helpdesk.config import API_PREFIX
18
+ from viewo_helpdesk.config import SECRET_KEY
19
+ from viewo_helpdesk.config import VIEWO_HELPDESK
20
+ from viewo_helpdesk.config import board
21
+ from viewo_helpdesk.config import configure
22
+ from viewo_helpdesk.message import Dialog
23
+ from viewo_helpdesk.message import Dialogs
24
+ from viewo_helpdesk.message import Message
25
+ from viewo_helpdesk.message import Messages
26
+ from viewo_helpdesk.message.action import start_conversion
27
+ from viewo_helpdesk.message.action import write_message
28
+ from viewo_helpdesk.message.collect import load_dialogs
29
+ from viewo_helpdesk.message.collect import load_messages
30
+ from viewo_helpdesk.message.collect import load_users
31
+ from viewo_helpdesk.message.collect import valid_dialog
32
+ from viewo_helpdesk.message.collect import valid_user
33
+ from viewo_helpdesk.message.path import userpath
34
+ from viewo_helpdesk.message.serialize import dump_message
35
+
36
+ __version__ = importlib.metadata.version('viewo-helpdesk')
37
+
38
+ ROOT = os.path.abspath(utilo.join(os.path.dirname(__file__), '..'))
@@ -0,0 +1,26 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import os
11
+
12
+ import utilo
13
+
14
+ import viewo_helpdesk
15
+ import viewo_helpdesk.app
16
+ import viewo_helpdesk.config
17
+
18
+ CONFIG = {
19
+ viewo_helpdesk.config.VIEWO_HELPDESK:
20
+ os.environ.get(
21
+ viewo_helpdesk.config.VIEWO_HELPDESK,
22
+ utilo.join(utilo.tmpdir(viewo_helpdesk.ROOT), 'viewo_helpdesk'),
23
+ )
24
+ }
25
+
26
+ instance = viewo_helpdesk.app.create(CONFIG) # pylint:disable=C0103
@@ -0,0 +1,8 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
@@ -0,0 +1,101 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import functools
11
+ import http
12
+
13
+ import flask
14
+ import flask_login
15
+ import utilo
16
+
17
+ import viewo_helpdesk
18
+ import viewo_helpdesk.config
19
+
20
+ api_auth = flask.Blueprint('api_auth', __name__) # pylint:disable=C0103
21
+ api_message = flask.Blueprint('api_message', __name__) # pylint:disable=C0103
22
+
23
+ __all__ = ['api_auth', 'api_message', 'auth', 'delete', 'post', 'present']
24
+
25
+
26
+ def dump(data, name='', uri='') -> str:
27
+ uri = uri if uri else flask.request.path
28
+ name = name if name else 'data'
29
+ data = utilo.simplify(data) # pylint:disable=E1101
30
+ connected = {'uri': uri, name: data}
31
+ json = flask.jsonify(connected)
32
+ return json
33
+
34
+
35
+ def success(message: str = 'completed', **args):
36
+ result = flask.jsonify({
37
+ 'message': message,
38
+ **args,
39
+ })
40
+ return result, http.HTTPStatus.OK
41
+
42
+
43
+ def notfound(message: str):
44
+ result = flask.jsonify({
45
+ 'error': 'not found',
46
+ 'message': message,
47
+ })
48
+ return result, http.HTTPStatus.NOT_FOUND
49
+
50
+
51
+ def bad(message: str):
52
+ result = flask.jsonify({
53
+ 'error': 'bad request',
54
+ 'message': message,
55
+ })
56
+ return result, http.HTTPStatus.BAD_REQUEST
57
+
58
+
59
+ def internal(message: str):
60
+ result = flask.jsonify({
61
+ 'error': 'internal',
62
+ 'message': message,
63
+ })
64
+ return result, http.HTTPStatus.INTERNAL_SERVER_ERROR
65
+
66
+
67
+ def api_call(path):
68
+ return viewo_helpdesk.config.API_PREFIX + path
69
+
70
+
71
+ def valid_user(function):
72
+
73
+ @functools.wraps(function)
74
+ def decorated_function(*args, **kwargs):
75
+ userid = kwargs['userid']
76
+ currentuser = flask_login.current_user
77
+ if not currentuser.is_authenticated:
78
+ return bad('login required')
79
+ if not userid and not currentuser.is_admin:
80
+ return notfound('not accessable')
81
+ if userid and not currentuser.is_admin:
82
+ if not viewo_helpdesk.valid_user(userid):
83
+ return notfound(f'could not locate `{userid}`')
84
+ if currentuser.get_id() != userid:
85
+ return notfound('not accessable')
86
+ return function(*args, **kwargs)
87
+
88
+ return decorated_function
89
+
90
+
91
+ def valid_dialog(function):
92
+
93
+ @functools.wraps(function)
94
+ def decorated_function(*args, **kwargs):
95
+ userid = kwargs['userid']
96
+ date = kwargs['date']
97
+ if not viewo_helpdesk.valid_dialog(userid, date):
98
+ return notfound(f'could not locate `{userid}` `{date}`')
99
+ return function(*args, **kwargs)
100
+
101
+ return decorated_function
@@ -0,0 +1,102 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import dataclasses
11
+ import functools
12
+ import http
13
+
14
+ import flask
15
+ import flask_login
16
+
17
+ import viewo_helpdesk.api
18
+ import viewo_helpdesk.config
19
+
20
+ NO_ACCESS = 'LOGIN REQUIRED'
21
+
22
+
23
+ @dataclasses.dataclass
24
+ class FlaskUser(flask_login.UserMixin):
25
+ identifier: str = None
26
+
27
+ def get_id(self):
28
+ return self.identifier
29
+
30
+ @property
31
+ def is_admin(self):
32
+ return self.identifier == viewo_helpdesk.config.ADMIN_NAME
33
+
34
+
35
+ def create_loginmanager(app):
36
+ loginmanager = flask_login.LoginManager()
37
+ loginmanager.login_view = 'api_auth.show_login'
38
+ loginmanager.init_app(app)
39
+
40
+ loginmanager._user_callback = load_user # pylint:disable=W0212
41
+
42
+
43
+ def verify_password(user: str, password: str) -> bool:
44
+ if user == viewo_helpdesk.config.ADMIN_NAME:
45
+ if password == viewo_helpdesk.config.ADMIN_PASSWORD:
46
+ return True
47
+ return False
48
+
49
+
50
+ def login(user, password) -> bool:
51
+ if not verify_password(user, password):
52
+ return False
53
+ user = load_user(user)
54
+ flask_login.login_user(user)
55
+ return True
56
+
57
+
58
+ def load_user(userid):
59
+ return FlaskUser(identifier=userid)
60
+
61
+
62
+ @viewo_helpdesk.api.api_auth.route('/auth')
63
+ def show_login():
64
+ return NO_ACCESS, http.HTTPStatus.UNAUTHORIZED
65
+
66
+
67
+ @viewo_helpdesk.api.api_auth.route('/logout')
68
+ def logout():
69
+ flask_login.logout_user()
70
+ return 'DONE'
71
+
72
+
73
+ @viewo_helpdesk.api.api_auth.route('/auth', methods=['POST'])
74
+ def check_login():
75
+ if flask_login.current_user.is_authenticated:
76
+ return 'DONE'
77
+
78
+ user = flask.request.form['user']
79
+ password = flask.request.form['password']
80
+
81
+ # verify
82
+ if not verify_password(user, password):
83
+ return 'INVALID PASSWORD', http.HTTPStatus.NOT_FOUND
84
+
85
+ # login
86
+ login(user, password)
87
+ if flask_login.current_user.is_admin:
88
+ return flask.jsonify({'link': '/admin/messages/list'})
89
+ return 'DONE'
90
+
91
+
92
+ def admin_required(func):
93
+
94
+ @functools.wraps(func)
95
+ def decorated_view(*args, **kwargs):
96
+ if not flask_login.current_user.is_authenticated:
97
+ return flask.current_app.login_manager.unauthorized()
98
+ if not flask_login.current_user.is_admin:
99
+ return flask.current_app.login_manager.unauthorized()
100
+ return func(*args, **kwargs)
101
+
102
+ return decorated_view
@@ -0,0 +1,8 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
@@ -0,0 +1,49 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import flask
11
+ import flask_login
12
+ import utilo
13
+
14
+ import viewo_helpdesk
15
+ import viewo_helpdesk.api
16
+
17
+
18
+ @viewo_helpdesk.api.api_message.route('/dialog/add', methods=['POST'])
19
+ def message_add() -> str:
20
+ parent = flask.request.form.get('parent', None)
21
+ userid = flask.request.form.get('userid', None)
22
+ date = utilo.now()
23
+ title = flask.request.form.get('title', None)
24
+ text = flask.request.form.get('text', None)
25
+ category = flask.request.form.get('category', None)
26
+
27
+ new_dialog = parent is None
28
+ admin = flask_login.current_user.is_admin
29
+ if not admin:
30
+ userid = flask_login.current_user.get_id()
31
+
32
+ message = viewo_helpdesk.Message(
33
+ parent=None if new_dialog else parent,
34
+ userid=userid,
35
+ date=date,
36
+ title=title,
37
+ text=text,
38
+ writer=userid if not admin else None,
39
+ category=category,
40
+ )
41
+ if new_dialog:
42
+ viewo_helpdesk.start_conversion(message, current=date)
43
+ else:
44
+ viewo_helpdesk.write_message(message, current=date)
45
+
46
+ done = {'date': date}
47
+ uri = viewo_helpdesk.api_call(f'/dialog/{userid}/{date}')
48
+ dumped = viewo_helpdesk.api.dump(done, name='success', uri=uri)
49
+ return dumped
@@ -0,0 +1,43 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import viewo_helpdesk
11
+ import viewo_helpdesk.api
12
+ import viewo_helpdesk.api.auth
13
+
14
+
15
+ @viewo_helpdesk.api.api_message.route(
16
+ '/dialogs/<string(length=16):userid>',
17
+ methods=['GET'],
18
+ )
19
+ @viewo_helpdesk.api.valid_user
20
+ def dialogs(userid):
21
+ result = viewo_helpdesk.load_dialogs(userid)
22
+ dumped = viewo_helpdesk.api.dump(result, 'dialogs')
23
+ return dumped
24
+
25
+
26
+ @viewo_helpdesk.api.api_message.route('/dialogs', methods=['GET'])
27
+ @viewo_helpdesk.api.auth.admin_required
28
+ def get_dialog():
29
+ result = viewo_helpdesk.load_dialogs()
30
+ dumped = viewo_helpdesk.api.dump(result, 'dialogs')
31
+ return dumped
32
+
33
+
34
+ @viewo_helpdesk.api.api_message.route(
35
+ '/dialog/<string(length=16):userid>/<int:date>',
36
+ methods=['GET'],
37
+ )
38
+ @viewo_helpdesk.api.valid_user
39
+ @viewo_helpdesk.api.valid_dialog
40
+ def dialog_get(userid: str, date: int):
41
+ messages = viewo_helpdesk.load_messages(userid, date)
42
+ dumped = viewo_helpdesk.api.dump(messages, 'messages')
43
+ return dumped
viewo_helpdesk/app.py ADDED
@@ -0,0 +1,45 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import flask
11
+ import flask_bootstrap
12
+
13
+ import viewo_helpdesk
14
+ import viewo_helpdesk.api.auth
15
+ import viewo_helpdesk.api.post
16
+ import viewo_helpdesk.api.present
17
+ from viewo_helpdesk.api import api_auth
18
+ from viewo_helpdesk.api import api_message
19
+ from viewo_helpdesk.view import * # pylint:disable=wildcard-import
20
+ from viewo_helpdesk.view import view_login
21
+ from viewo_helpdesk.view import view_user
22
+
23
+
24
+ def create(config=None) -> flask.Flask:
25
+ appi = flask.Flask(__name__)
26
+ appi.secret_key = viewo_helpdesk.SECRET_KEY
27
+
28
+ viewo_helpdesk.api.auth.create_loginmanager(appi)
29
+
30
+ appi.config.setdefault('BOOTSTRAP_SERVE_LOCAL', True)
31
+ flask_bootstrap.Bootstrap5(app=appi)
32
+
33
+ if config:
34
+ appi.config.update(config)
35
+
36
+ # view
37
+ appi.register_blueprint(view_admin)
38
+ appi.register_blueprint(view_login)
39
+ appi.register_blueprint(view_user)
40
+
41
+ # api
42
+ appi.register_blueprint(api_auth, url_prefix=viewo_helpdesk.API_PREFIX)
43
+ appi.register_blueprint(api_message, url_prefix=viewo_helpdesk.API_PREFIX)
44
+
45
+ return appi
viewo_helpdesk/cli.py ADDED
@@ -0,0 +1,76 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import argparse
11
+ import collections
12
+ import sys
13
+
14
+ import utilo
15
+
16
+
17
+ def main():
18
+ config = eval_cli()
19
+ # setup logging
20
+ utilo.level_setup(level=config.verbose)
21
+ app = create_app()
22
+ # run app
23
+ app.run(
24
+ host=config.host,
25
+ port=config.port,
26
+ debug=config.debug,
27
+ )
28
+
29
+
30
+ Config = collections.namedtuple(
31
+ 'Config',
32
+ 'host, port, debug, verbose',
33
+ )
34
+
35
+
36
+ def eval_cli():
37
+ parser = argparse.ArgumentParser()
38
+ parser.add_argument('--host', default='localhost', help='run on url')
39
+ parser.add_argument('--port', default=5000, help='run on port')
40
+ parser.add_argument(
41
+ '--debug',
42
+ action='store_true',
43
+ help='run in debug mode',
44
+ )
45
+ parser.add_argument(
46
+ '--verbose',
47
+ '-V',
48
+ action='count',
49
+ default=0,
50
+ help='define level of logging',
51
+ )
52
+ parser.add_argument(
53
+ '--version',
54
+ action='store_true',
55
+ help='print version and quit',
56
+ )
57
+ argv = parser.parse_args()
58
+ if argv.version:
59
+ import viewo_helpdesk
60
+ utilo.log(viewo_helpdesk.__version__)
61
+ sys.exit(utilo.SUCCESS)
62
+ result = Config(
63
+ argv.host,
64
+ int(argv.port),
65
+ argv.debug,
66
+ argv.verbose,
67
+ )
68
+ return result
69
+
70
+
71
+ def create_app():
72
+ import viewo_helpdesk.config
73
+ config = viewo_helpdesk.config.validate()
74
+ import viewo_helpdesk.app
75
+ result = viewo_helpdesk.app.create(config=config)
76
+ return result
@@ -0,0 +1,52 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import os
11
+ import sys
12
+
13
+ import configos
14
+ import flask
15
+ import utilo
16
+
17
+ VIEWO_HELPDESK = 'VIEWO_HELPDESK'
18
+
19
+ ADMIN_NAME = configos.env('ADMIN_NAME', default='admin')
20
+ ADMIN_PASSWORD = configos.env('ADMIN_PASSWORD', default='secret') # nosec
21
+
22
+ SECRET_KEY = b'helmut_max_power_abs29.nsTODOThisIsVerySecreyISwarTODO'
23
+
24
+ API_PREFIX = '/api/v0'
25
+
26
+
27
+ def helpdesk() -> str:
28
+ path = flask.current_app.config[VIEWO_HELPDESK]
29
+ os.makedirs(path, exist_ok=True)
30
+ return path
31
+
32
+
33
+ def board() -> str:
34
+ path = utilo.join(helpdesk(), 'messages')
35
+ os.makedirs(path, exist_ok=True)
36
+ return path
37
+
38
+
39
+ def configure(path):
40
+ flask.current_app.config[VIEWO_HELPDESK] = path
41
+
42
+
43
+ def validate():
44
+ try:
45
+ _ = os.environ[VIEWO_HELPDESK]
46
+ except KeyError:
47
+ utilo.error(f'could not start app, define `{VIEWO_HELPDESK}`')
48
+ sys.exit(utilo.FAILURE)
49
+ config = {
50
+ VIEWO_HELPDESK: os.environ[VIEWO_HELPDESK],
51
+ }
52
+ return config
@@ -0,0 +1,41 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import pytest
11
+
12
+ import viewo_helpdesk.api.auth
13
+ import viewo_helpdesk.app
14
+
15
+
16
+ @pytest.fixture
17
+ def appi(td):
18
+ """Create and configure a new app instance for each test."""
19
+ # create the app with common test config
20
+ created = viewo_helpdesk.app.create(config={
21
+ 'VIEWO_HELPDESK': td.tmpdir,
22
+ 'TESTING': True,
23
+ })
24
+ with created.app_context():
25
+ yield created
26
+
27
+
28
+ @pytest.fixture
29
+ def client(appi, mp): # pylint:disable=W0621
30
+ """A test client for the app."""
31
+ with mp.context() as context:
32
+
33
+ def verify_password(user: str, password: str) -> bool: # pylint:disable=W0613
34
+ return True
35
+
36
+ context.setattr(
37
+ viewo_helpdesk.api.auth,
38
+ 'verify_password',
39
+ verify_password,
40
+ )
41
+ yield appi.test_client()
@@ -0,0 +1,38 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import dataclasses
11
+
12
+
13
+ @dataclasses.dataclass
14
+ class Message:
15
+ """\
16
+ >>> Message()
17
+ Message(...)
18
+ """
19
+ parent: int = None
20
+ userid: str = None
21
+ date: int = None
22
+ title: str = None
23
+ text: str = None
24
+ writer: str = None
25
+ category: int = None
26
+
27
+
28
+ Messages = list[Message]
29
+
30
+
31
+ @dataclasses.dataclass
32
+ class Dialog:
33
+ userid: str = None
34
+ date: int = None
35
+ title: str = None
36
+
37
+
38
+ Dialogs = list[Dialog]
@@ -0,0 +1,52 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import os
11
+
12
+ import utilo
13
+
14
+ import viewo_helpdesk
15
+ import viewo_helpdesk.message
16
+ import viewo_helpdesk.message.path
17
+ import viewo_helpdesk.message.serialize
18
+
19
+
20
+ def delete_message(userid: str, date: int): # pylint:disable=W0613
21
+ pass
22
+
23
+
24
+ def delete_history(userid: str): # pylint:disable=W0613
25
+ pass
26
+
27
+
28
+ def start_conversion(
29
+ message: viewo_helpdesk.message.Message,
30
+ current: int = None,
31
+ ) -> int:
32
+ current = f'{utilo.now()}' if current is None else f'{current}'
33
+ outpath = utilo.join(viewo_helpdesk.userpath(message.userid), current)
34
+ # start new conversion folder
35
+ os.makedirs(outpath, exist_ok=True)
36
+ first_message = utilo.join(outpath, current)
37
+ dumped = viewo_helpdesk.dump_message(message)
38
+ utilo.file_create(first_message, dumped)
39
+ return current
40
+
41
+
42
+ def write_message(message: viewo_helpdesk.message.Message, current: int = None):
43
+ current = f'{utilo.now()}' if current is None else f'{current}'
44
+ if message.writer is None:
45
+ current = f'{current}!'
46
+ dumped = viewo_helpdesk.dump_message(message)
47
+ outpath = utilo.join(
48
+ viewo_helpdesk.userpath(message.userid),
49
+ f'{message.parent}',
50
+ current,
51
+ )
52
+ utilo.file_create(outpath, dumped)
@@ -0,0 +1,109 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import os
11
+
12
+ import utilo
13
+
14
+ import viewo_helpdesk
15
+ import viewo_helpdesk.config
16
+
17
+
18
+ def load_messages(userid: str, date: int) -> 'viewo_helpdesk.Messages':
19
+ date = f'{date}'
20
+ board = viewo_helpdesk.board()
21
+ path = utilo.join(board, userid, date)
22
+ dates = utilo.file_list(path)
23
+ # remove admin mark to clarify date
24
+ dates = [item.replace('!', '') for item in dates]
25
+ loaded = [load_message(userid, date, msgdate) for msgdate in dates]
26
+ # sort by date
27
+ loaded.sort(key=lambda x: x.date)
28
+ return loaded
29
+
30
+
31
+ def load_message(
32
+ userid: str,
33
+ start: int,
34
+ date: str = None,
35
+ ) -> 'viewo_helpdesk.Message':
36
+ # load header if no date is given
37
+ date = date if date else start
38
+ start, date = f'{start}', f'{date}'
39
+ board = viewo_helpdesk.board()
40
+ message = viewo_helpdesk.Message(
41
+ userid=userid,
42
+ parent=start,
43
+ date=int(date),
44
+ )
45
+ path = utilo.join(board, userid, start)
46
+ if os.path.exists(utilo.join(path, date)):
47
+ # user message
48
+ path = utilo.join(path, date)
49
+ message.writer = userid
50
+ else:
51
+ # admin message
52
+ path = utilo.join(path, f'{date}!')
53
+ message_raw = utilo.file_read(path)
54
+ title, text = message_raw.split('\n\n', maxsplit=1)
55
+ if title != 'None':
56
+ message.title = title
57
+ message.text = text
58
+ return message
59
+
60
+
61
+ def load_dialogs(user: str = None) -> 'viewo_helpdesk.Dialogs':
62
+ board = viewo_helpdesk.board()
63
+ result = []
64
+ users = utilo.directory_list(board) if user is None else [user] # pylint:disable=E1101
65
+ for userid in users:
66
+ dialogs = utilo.directory_list(utilo.join(board, userid)) # pylint:disable=E1101
67
+ for dialog in dialogs:
68
+ dialog = int(dialog)
69
+ title = load_message(userid, dialog, dialog).title
70
+ result.append(
71
+ viewo_helpdesk.Dialog(
72
+ userid=userid,
73
+ date=dialog,
74
+ title=title,
75
+ ))
76
+ return result
77
+
78
+
79
+ def load_users() -> list:
80
+ board = viewo_helpdesk.board()
81
+ users = utilo.file_list(board)
82
+ return users
83
+
84
+
85
+ def valid_user(userid: str) -> bool:
86
+ board = viewo_helpdesk.board()
87
+ userpath = utilo.join(board, userid)
88
+ if not os.path.exists(userpath):
89
+ return False
90
+ return True
91
+
92
+
93
+ def valid_dialog(userid: str, date: int) -> bool:
94
+ if not valid_user(userid):
95
+ return False
96
+ date = f'{date}'
97
+ board = viewo_helpdesk.board()
98
+ dialogpath = utilo.join(board, userid, date)
99
+ if not os.path.exists(dialogpath):
100
+ return False
101
+ return True
102
+
103
+
104
+ def load_after(date: int, userid: int = None): # pylint:disable=W0613
105
+ pass
106
+
107
+
108
+ def load_before(data: int, userid: int = None): # pylint:disable=W0613
109
+ pass
@@ -0,0 +1,17 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import utilo
11
+
12
+ import viewo_helpdesk
13
+
14
+
15
+ def userpath(userid: str) -> str:
16
+ result = utilo.join(viewo_helpdesk.board(), userid)
17
+ return result
@@ -0,0 +1,15 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import viewo_helpdesk.message
11
+
12
+
13
+ def dump_message(message: viewo_helpdesk.message.Message) -> str:
14
+ raw = f'{message.title}\n\n{message.text}'
15
+ return raw
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="de">
3
+
4
+ <body>
5
+
6
+ {% if current_user %}
7
+ <a href="{{ url_for('api_auth.logout') }}">Logout</a>
8
+ {% endif %}
9
+
10
+ {% block content %}
11
+
12
+ {% endblock %}
13
+ </body>
@@ -0,0 +1,33 @@
1
+ {% extends 'admin/base.html' %}
2
+
3
+ {% block content %}
4
+ <h2>Nachrichten</h2>
5
+ <hr>
6
+ {% if not dialogs %}
7
+ Keine Nachrichten verfügbar.
8
+ {% else %}
9
+ <table class="small_table table table-striped table-bordered">
10
+ <thead>
11
+ <tr>
12
+ <th>Title</th>
13
+ <th>Datum</th>
14
+ <th class="small">Action</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ {% for dialog in dialogs %}
19
+ <tr>
20
+ <td>{{dialog['title']}}</td>
21
+ <td>{{dialog['date']}}</td>
22
+ <td>
23
+ <a href="{{ url_for('view_admin.messages_show', userid=dialog['userid'], date=dialog['date']) }}">
24
+ Öffnen</a>
25
+ </td>
26
+ </tr>
27
+ {% endfor %}
28
+ </tbody>
29
+ </table>
30
+
31
+ {% endif %}
32
+
33
+ {% endblock %}
@@ -0,0 +1,5 @@
1
+ <h2>Nachrichten</h2>
2
+ <ul>
3
+ <li><a href="{{ url_for('view_admin.messages_list') }}">Messages</a></li>
4
+ </ul>
5
+ <hr>
@@ -0,0 +1,25 @@
1
+ <h2>Nachrichten</h2>
2
+
3
+ <ul>
4
+ <li><a href="{{ url_for('view_admin.messages_list') }}">Messages</a></li>
5
+ </ul>
6
+ <hr />
7
+
8
+ {% for message in messages %}
9
+ {% if message['title'] %}
10
+ <h3>{{message['title']}}</h3>
11
+ {% endif %}
12
+
13
+ {% if message['writer'] %}
14
+ User: {{message['writer']}}<br />
15
+ {% else %}
16
+ User: Admin<br />
17
+ {% endif %}
18
+
19
+ Date: {{message['date']}}<br />
20
+ <p>{{message['text']}}</p>
21
+ ____________________<br />
22
+ {% endfor %}
23
+
24
+ <a href="{{ url_for('view_admin.messages_show', userid=dialog['userid'], date=dialog['date']) }}">
25
+ Anworten</a>
@@ -0,0 +1,19 @@
1
+ <!doctype html>
2
+ <html lang="de">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport"
6
+ content="width=device-width, initial-scale=1">
7
+
8
+ <title>{% block title %}viewo helpdesk{% endblock %}</title>
9
+
10
+ {{ bootstrap.load_css() }}
11
+ </head>
12
+ <body>
13
+
14
+ {% block content %}{% endblock %}
15
+
16
+ {{ bootstrap.load_js() }}
17
+
18
+ </body>
19
+ </html>
@@ -0,0 +1,16 @@
1
+ {% macro button(id='', caption='', img='', alt='', style='', class='', data_dismiss='', onclick='', padding='', width='100%', height='100%') -%}
2
+ <button type="button" {% if id %} id="{{ id }}" {% endif %}
3
+ {% if style %} style="{{ style }}" {% endif %}
4
+ {% if class %} class="{{ class}}" {% endif %}
5
+ {% if data_dismiss %} data-dismiss="{{ data_dismiss }}" {% endif %}
6
+ {% if onclick %} onclick="{{ onclick }}" {% endif %}
7
+ >
8
+ {% if img %}
9
+ <img src="{{ url_for('static', filename=img) }}" {% if alt %}
10
+ alt="{{ alt }}" {% endif %} width="{{width}}" height="{{height}}" />
11
+ {% endif %}
12
+ {% if caption %}
13
+ {{ caption }}
14
+ {% endif %}
15
+ </button>
16
+ {%- endmacro %}
@@ -0,0 +1,78 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% from 'helper.mac' import button %}
4
+
5
+ {% block title %}Admin - Login{% endblock %}
6
+
7
+ {% block content %}
8
+ <h1>Login</h1>
9
+
10
+ <div class="container" id="nogoodnews">
11
+ {% for message in get_flashed_messages() %}
12
+ <div class="alert alert-warning">
13
+ {{ button(caption='&times;', class='close', data_dismiss='alert') }}
14
+ {{ message }}
15
+ </div>
16
+ {% endfor %}
17
+ </div>
18
+
19
+ <div class="container">
20
+ <form method="POST" id="validate_login" role="form" class="form-horizontal">
21
+ <div class="form-group">
22
+ <labbel for="user" class="col-sm-2 control-label">Benutzer:</labbel>
23
+ <div class="col-sm-3">
24
+ <input type="text" class="form-control" name="user" value="{{user}}">
25
+ </div>
26
+ </div>
27
+
28
+ <div class="form-group">
29
+ <labbel for="password" class="col-sm-2 control-label">Passwort:</labbel>
30
+ <div class="col-sm-3">
31
+ <input type="password" class="form-control" name="password" value="{{password}}">
32
+ </div>
33
+ </div>
34
+
35
+ <div class="form-group">
36
+ <labbel class="col-sm-2 control-label"></labbel>
37
+ <div class="col-sm-3">
38
+ <button type="submit" class="btn btn-default">Anmelden</button>
39
+ </div>
40
+ </div>
41
+ </form>
42
+ </div>
43
+ {% endblock %}
44
+
45
+ {% block scripts %}
46
+ {{ super() }}
47
+ <script type="text/javascript">
48
+ $("#validate_login").submit(function (event) {
49
+ event.preventDefault();
50
+ let user = $("input[name='user']")[0].value
51
+ let password = $("input[name='password']")[0].value
52
+ login(user, password)
53
+ });
54
+
55
+ function login(user, password) {
56
+ let url = `/api/v0/auth`
57
+ $.ajax(url, {
58
+ method: "POST",
59
+ data: { 'user': user, 'password': password },
60
+ success: function (response) {
61
+ window.location.replace(response['link'])
62
+ },
63
+ error: function () {
64
+ user_error('invalid login data')
65
+ }
66
+ })
67
+ }
68
+
69
+ function user_error(message) {
70
+ let entry = `<div class="alert alert-warning">
71
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
72
+ ${message}
73
+ </div>`
74
+ $('#nogoodnews').append(entry)
75
+ }
76
+
77
+ </script>
78
+ {% endblock %}
File without changes
@@ -0,0 +1,16 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import flask
11
+
12
+ view_admin = flask.Blueprint('view_admin', __name__) # pylint:disable=C0103
13
+ view_login = flask.Blueprint('view_login', __name__) # pylint:disable=C0103
14
+ view_user = flask.Blueprint('view_user', __name__) # pylint:disable=C0103
15
+
16
+ __all__ = ['admin', 'login', 'user', 'view_admin', 'view_login', 'view_user']
@@ -0,0 +1,53 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import flask
11
+ import flask_login
12
+
13
+ import viewo_helpdesk.api.auth
14
+ import viewo_helpdesk.message.collect
15
+ import viewo_helpdesk.view
16
+
17
+
18
+ @viewo_helpdesk.view.view_admin.route('/admin/messages/list')
19
+ @flask_login.login_required
20
+ def messages_list():
21
+ """Route public pages which are visible without any permissions."""
22
+ dialogs = viewo_helpdesk.message.collect.load_dialogs()
23
+ headers = [
24
+ viewo_helpdesk.message.collect.load_message(item.userid, item.date)
25
+ for item in dialogs
26
+ ]
27
+ return flask.render_template('admin/index.html', dialogs=headers)
28
+
29
+
30
+ @viewo_helpdesk.view.view_admin.route(
31
+ '/admin/messages/reply/<string(length=16):userid>/<int:date>',
32
+ methods=['GET'],
33
+ )
34
+ @flask_login.login_required
35
+ def messages_reply(userid: str, date: int): # pylint:disable=W0612,W0613
36
+ # messages = viewo_helpdesk.message.collect.load_messages(userid, date)
37
+ pass
38
+
39
+
40
+ @viewo_helpdesk.view.view_admin.route(
41
+ '/admin/messages/show/<string(length=16):userid>/<int:date>',
42
+ methods=['GET'],
43
+ )
44
+ @flask_login.login_required
45
+ def messages_show(userid: str, date: int):
46
+ messages = viewo_helpdesk.message.collect.load_messages(userid, date)
47
+ dialog = viewo_helpdesk.Dialog(userid, date)
48
+ rendered = flask.render_template(
49
+ 'admin/show.html',
50
+ messages=messages,
51
+ dialog=dialog,
52
+ )
53
+ return rendered
@@ -0,0 +1,31 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import flask
11
+ import flask_login
12
+
13
+ import viewo_helpdesk.api.auth
14
+ import viewo_helpdesk.view
15
+
16
+
17
+ @viewo_helpdesk.view.view_login.route('/admin/login')
18
+ def login_show():
19
+ """Route public pages which are visible without any permissions."""
20
+ if flask_login.current_user.get_id() is not None:
21
+ return flask.redirect(flask.url_for('view_admin.messages_list'))
22
+ return flask.render_template('login.html')
23
+
24
+
25
+ @viewo_helpdesk.view.view_login.route('/admin/login', methods=['POST'])
26
+ def login_check():
27
+ user = flask.request.form.get('user', None)
28
+ password = flask.request.form.get('password', None)
29
+ if not viewo_helpdesk.api.auth.login(user, password):
30
+ return flask.render_template('login.html')
31
+ return flask.redirect(flask.url_for('view_admin.messages_list'))
@@ -0,0 +1,8 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
5
+ # This file is property of Helmut Konrad Schewe. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: viewo_helpdesk
3
+ Version: 1.0.0
4
+ Author-email: Helmut Konrad Schewe <helmutus@outlook.com>
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/anaticulae/viewo-helpdesk
7
+ Project-URL: Repository, https://github.com/anaticulae/viewo-helpdesk
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: bootstrap-flask<3.0.0,>=2.6.0
15
+ Requires-Dist: configos<2.0.0,>=1.0.4
16
+ Requires-Dist: flask-login<1.0.0,>=0.6.3
17
+ Requires-Dist: flask<4.0.0,>=3.1.3
18
+ Requires-Dist: flask_bootstrap<4.0.0.0,>=3.3.7.1
19
+ Requires-Dist: utilo<3.0.0,>=2.112.1
20
+ Provides-Extra: dev
21
+ Requires-Dist: utilotest==1.1.1; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # viewo_helpdesk
@@ -0,0 +1,35 @@
1
+ viewo_helpdesk/__init__.py,sha256=_BWSdJ9esxh4WHGkO5yhXKQHPVJUtkCBahploX68feQ,1699
2
+ viewo_helpdesk/__main__.py,sha256=KKau-0PKmRFwaMbRys71U3BLt2OKZ5QmxJx6MMzkhqs,942
3
+ viewo_helpdesk/__patch__.py,sha256=TM9PAYPmQhbW1HY3Vx-bS5rXe132Z02TPBxFMad80Dk,552
4
+ viewo_helpdesk/app.py,sha256=_-DpE7y0k8Vz0QWfCYzTUqlyC4-IPEV0hy9OctUqOTc,1587
5
+ viewo_helpdesk/cli.py,sha256=jdWNe8tyuzrKw-mQajMYuvKAsZSXm9SQXx6UPKONbe0,2008
6
+ viewo_helpdesk/config.py,sha256=IxfRcnQBbvRGcrNAIMUejUarMZMRQW3d9astq3PZuAg,1488
7
+ viewo_helpdesk/fixtures.py,sha256=wwLC5MwJyxF-vqUCDfbNGOs4Y6EiE_vLYn04VGJzeS0,1352
8
+ viewo_helpdesk/api/__init__.py,sha256=MyfdL2O_wuLk8x14ROS-bZqFg2iZSKXSnQbFSth-HwU,3015
9
+ viewo_helpdesk/api/auth.py,sha256=LdEHXE00ERTzASqWNCy8FdGR6Yd1TzRPGZQUSE0gB1M,2800
10
+ viewo_helpdesk/api/delete.py,sha256=TM9PAYPmQhbW1HY3Vx-bS5rXe132Z02TPBxFMad80Dk,552
11
+ viewo_helpdesk/api/post.py,sha256=nci1-lVcMfW0ocm4T3aO0oSXWCphHfVuy7wdFS4X6DQ,1749
12
+ viewo_helpdesk/api/present.py,sha256=31hBdxZGf7XHP5dd-03pi6iozYzzWa1ZGHW4NCdakNg,1514
13
+ viewo_helpdesk/message/__init__.py,sha256=exqIdIi5xHWcGmX_oEDRhecqcQvb3gnrWKkX9q6wrm8,979
14
+ viewo_helpdesk/message/action.py,sha256=V5SDoS337ae5MusHxknVJwF_BrFilthDfT2Z12cHd6o,1766
15
+ viewo_helpdesk/message/collect.py,sha256=-fo3lRztOCs1QQ3-iPOk-vdZeLv0ossvAPNctTf_guE,3308
16
+ viewo_helpdesk/message/path.py,sha256=Lu6jjUljsLJx2W7mU4odOZptJBDMVbf52j2ttoGQ1ws,699
17
+ viewo_helpdesk/message/serialize.py,sha256=rErbc3L3fSz_--3ssfYJQh3RGrM-VY2VYcRX2JptBy8,713
18
+ viewo_helpdesk/templates/base.html,sha256=Two9-YlQ55FGUdWaqewfqH-MB-rEnlinkMepnvgisXY,350
19
+ viewo_helpdesk/templates/helper.mac,sha256=onguVAgxweL9p9CFa61Qk4fk_i3h9SsXxlOuKDUkvFE,698
20
+ viewo_helpdesk/templates/login.html,sha256=Ka_-QDpIJJjmbq1-boEfGWOPE6BJz5qDRAk4RRFtGuE,2358
21
+ viewo_helpdesk/templates/user.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ viewo_helpdesk/templates/admin/base.html,sha256=9dyd8Wg_RHnK30ZHMiQqY7evUgs0_7PR_kBHXoXxTUY,195
23
+ viewo_helpdesk/templates/admin/index.html,sha256=sJmvv5VkAaOiweBvbSGzFXjXoSKYt-nKMLYeZF5Wem0,762
24
+ viewo_helpdesk/templates/admin/reply.html,sha256=BUysg0eT1PEL_mX_-OEDkwwvftuTO9ixV0GCJBDpnOs,115
25
+ viewo_helpdesk/templates/admin/show.html,sha256=L7x6QlLodI72nk09twiDi1Vvw0TyDjGLap_kltcRQDg,538
26
+ viewo_helpdesk/view/__init__.py,sha256=NMy7eEjsXY8S5FjpbqOzoWOSTcvcI_ggshDKniZOOSw,875
27
+ viewo_helpdesk/view/admin.py,sha256=ts26rAWYmiFH4uOgMdO56BQ0byLUiC5fpsL9T6IFdt4,1906
28
+ viewo_helpdesk/view/login.py,sha256=VgftdbopEbYYSiBm7rlrHXok4txnWHvQU1MDt-v8f5w,1339
29
+ viewo_helpdesk/view/user.py,sha256=TM9PAYPmQhbW1HY3Vx-bS5rXe132Z02TPBxFMad80Dk,552
30
+ viewo_helpdesk-1.0.0.dist-info/licenses/LICENSE,sha256=9jV_XivjSpyzpEYIFKZGcjDzX8invw3EHEJsGXmGJbA,1077
31
+ viewo_helpdesk-1.0.0.dist-info/METADATA,sha256=hzhnGwt-vE-f_iedC7TNkCh6VQH5n3ilqUyMoOKdMN0,870
32
+ viewo_helpdesk-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
33
+ viewo_helpdesk-1.0.0.dist-info/entry_points.txt,sha256=Bw7baWjSPUNt3Gb7gi-pu-DsOgbcJUtihhmxGTKRSzw,59
34
+ viewo_helpdesk-1.0.0.dist-info/top_level.txt,sha256=KHOSvNubdgwrbDv4TTRsCr3WPYnMv2kmDwx-118c6Fw,15
35
+ viewo_helpdesk-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ viewo_helpdesk = viewo_helpdesk.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Helmut Konrad Schewe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ viewo_helpdesk