viewo-talk 1.0.0__tar.gz

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,11 @@
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
+ graft viewo_talk/static
11
+ graft viewo_talk/templates
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: viewo_talk
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_talk
7
+ Project-URL: Repository, https://github.com/anaticulae/viewo_talk
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
+ Requires-Dist: flask-bootstrap<4.0.0.0,>=3.3.7.1
14
+ Requires-Dist: flask<4.0.0,>=3.1.3
15
+ Requires-Dist: utilo<3.0.0,>=2.112.1
16
+ Requires-Dist: viewo_api<2.0.0,>=1.0.1
17
+ Provides-Extra: dev
18
+ Requires-Dist: selenium<5.0.0,>=4.51.0; extra == "dev"
19
+ Requires-Dist: utilotest<2.0.0,>=1.1.1; extra == "dev"
20
+
21
+ # viewo_talk
@@ -0,0 +1 @@
1
+ # viewo_talk
@@ -0,0 +1,87 @@
1
+ [project]
2
+ name = "viewo_talk"
3
+ version = "1.0.0"
4
+ description = ""
5
+ requires-python = ">=3.12"
6
+ authors = [
7
+ { name = "Helmut Konrad Schewe", email = "helmutus@outlook.com" },
8
+ ]
9
+ dependencies = [
10
+ "flask-bootstrap>=3.3.7.1,<4.0.0.0",
11
+ "flask>=3.1.3,<4.0.0",
12
+ "utilo>=2.112.1,<3.0.0",
13
+ "viewo_api>=1.0.1,<2.0.0",
14
+ ]
15
+ keywords = []
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
20
+ ]
21
+ license = "MIT"
22
+ license-files = [
23
+ "LICENSE",
24
+ ]
25
+
26
+ [project.readme]
27
+ file = "README"
28
+ content-type = "text/markdown"
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "selenium>=4.51.0,<5.0.0",
33
+ "utilotest>=1.1.1,<2.0.0",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/anaticulae/viewo_talk"
38
+ Repository = "https://github.com/anaticulae/viewo_talk"
39
+
40
+ [project.scripts]
41
+ viewo_talk = "viewo_talk.cli:main"
42
+
43
+ [build-system]
44
+ requires = [
45
+ "setuptools>=82.0.1",
46
+ "wheel>=0.46.3",
47
+ ]
48
+ build-backend = "setuptools.build_meta"
49
+
50
+ [tool.semantic_release]
51
+ version_toml = [
52
+ "pyproject.toml:project.version",
53
+ ]
54
+
55
+ [tool.semantic_release.changelog]
56
+ mode = "init"
57
+ output_format = "md"
58
+
59
+ [tool.semantic_release.changelog.default_templates]
60
+ changelog_file = "CHANGELOG"
61
+
62
+ [tool.semantic_release.commit_parser_options]
63
+ patch_tags = [
64
+ "fix",
65
+ "perf",
66
+ "build",
67
+ "chore",
68
+ "ci",
69
+ "docs",
70
+ "style",
71
+ "refactor",
72
+ "test",
73
+ "deps",
74
+ ]
75
+
76
+ [tool.setuptools.packages.find]
77
+ where = [
78
+ ".",
79
+ ]
80
+ include = [
81
+ "viewo_talk",
82
+ "viewo_talk.api",
83
+ "viewo_talk.plan",
84
+ ]
85
+ exclude = [
86
+ "tests/*",
87
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,16 @@
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 viewo_talk.plan
11
+ import viewo_talk.talk
12
+
13
+
14
+ def test_collect():
15
+ collected = viewo_talk.talk.collect(viewo_talk.plan)
16
+ assert len(collected) >= 1
@@ -0,0 +1,24 @@
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 importlib.metadata
11
+ import os
12
+
13
+ __version__ = importlib.metadata.version('viewo-talk')
14
+
15
+ ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
16
+
17
+ # pylint:disable=C0413
18
+ from viewo_talk.action import ActionMixin # isort:skip
19
+ from viewo_talk.action import Message # isort:skip
20
+ from viewo_talk.action import Question # isort:skip
21
+ from viewo_talk.action import pth # isort:skip
22
+ from viewo_talk.api import api_talk # isort:skip
23
+ from viewo_talk.app import register_talkme # isort:skip
24
+ from viewo_talk.talk import update # isort:skip
@@ -0,0 +1,13 @@
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 viewo_talk.app
11
+
12
+ if __name__ == "__main__":
13
+ app = viewo_talk.app.create_app() # pylint:disable=C0103
@@ -0,0 +1,102 @@
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 dataclasses
11
+
12
+ import viewo_talk.config
13
+
14
+
15
+ @dataclasses.dataclass
16
+ class Action:
17
+ user: int = None
18
+ time: int = None
19
+ msgid: int = None
20
+ path: str = None
21
+ data: str = None
22
+
23
+
24
+ @dataclasses.dataclass
25
+ class Answer(Action):
26
+ question: int = None
27
+ answer: bool = False
28
+
29
+
30
+ @dataclasses.dataclass
31
+ class Message:
32
+ user: int = None
33
+ time: int = None
34
+ msgid: int = None
35
+ title: str = None
36
+ content: str = None
37
+ index: str = None
38
+
39
+ def json(self) -> dict:
40
+ result = {
41
+ 'name': self.__class__.__name__.upper(),
42
+ 'title': self.title,
43
+ 'content': self.content,
44
+ }
45
+ return result
46
+
47
+
48
+ @dataclasses.dataclass
49
+ class Question(Message):
50
+ """\
51
+ >>> Question(title='Magst du Brot?', index=10).json()
52
+ {'name': 'QUESTION', 'title': 'Magst du Brot?', 'content': None, 'index': 10}
53
+ """
54
+
55
+ def json(self) -> dict:
56
+ result = super().json()
57
+ result['index'] = self.index
58
+ return result
59
+
60
+
61
+ class ActionMixin:
62
+
63
+ def __init__(self, routes: list = None):
64
+ self.routes = routes if routes else []
65
+
66
+ def run(self, item):
67
+ pass
68
+
69
+ def register(self, talker):
70
+ self.send_msg = talker.send_msg
71
+ self.send_question = talker.send_question
72
+
73
+
74
+ def answer_split(raw: str):
75
+ raw = raw.strip()
76
+ return raw.split('\n\n', maxsplit=1)
77
+
78
+
79
+ def fromrequest(request) -> Action:
80
+ action = Action(
81
+ user=request.hashed,
82
+ time=request.time,
83
+ path=(request.method, request.path),
84
+ data=request.data,
85
+ msgid=msgid(path=request.path, method=request.method),
86
+ )
87
+ return action
88
+
89
+
90
+ def pth(path: str):
91
+ return f'{viewo_talk.config.API_PREFIX}{path}'
92
+
93
+
94
+ API_LISTEN = pth('/talktome')
95
+
96
+
97
+ def msgid(path, method='GET') -> str:
98
+ if method == 'POST':
99
+ return 'POST'
100
+ if path == API_LISTEN:
101
+ return 'LISTEN'
102
+ return None
@@ -0,0 +1,23 @@
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 os
11
+
12
+ import flask
13
+
14
+ import viewo_talk
15
+
16
+ api_talk = flask.Blueprint(
17
+ name='api_talk',
18
+ import_name=__name__,
19
+ static_folder=os.path.join(viewo_talk.ROOT, 'viewo_talk/static'),
20
+ template_folder=os.path.join(viewo_talk.ROOT, 'viewo_talk/templates'),
21
+ )
22
+
23
+ __all__ = ['api_talk', 'present']
@@ -0,0 +1,50 @@
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 flask
11
+ import viewo_api
12
+
13
+ import viewo_talk.action
14
+ import viewo_talk.api
15
+
16
+
17
+ @viewo_talk.api.api_talk.route('/talktome', methods=['GET'])
18
+ def receive_message() -> str:
19
+ userid = viewo_api.user_current()
20
+ messages = flask.current_app.talker.answers_pop(userid)
21
+ # convert to JSON
22
+ messages = [item.json() for item in messages]
23
+ data = {"messages": messages} if messages else {}
24
+ result = flask.jsonify(data)
25
+ return result
26
+
27
+
28
+ @viewo_talk.api.api_talk.route('/talktome', methods=['POST'])
29
+ def receive_answer() -> str:
30
+ try:
31
+ question = int(flask.request.form.get('question', None))
32
+ except (TypeError, ValueError):
33
+ return viewo_api.bad('invalid question')
34
+ answer = bool(flask.request.form.get('answer', None))
35
+ todo = create_answer(question, answer)
36
+ flask.current_app.talker.append(todo)
37
+ return 'done', 200
38
+
39
+
40
+ def create_answer(question: int, answer: bool):
41
+ request = viewo_api.request()
42
+ result = viewo_talk.action.Answer(
43
+ user=request.hashed,
44
+ time=request.time,
45
+ path=(request.method, request.path),
46
+ data=request.data,
47
+ answer=answer,
48
+ question=question,
49
+ )
50
+ return result
@@ -0,0 +1,77 @@
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 flask
11
+ import flask_bootstrap
12
+ import viewo_api
13
+
14
+ import viewo_talk
15
+ import viewo_talk.action
16
+ import viewo_talk.config
17
+ import viewo_talk.talk
18
+ from viewo_talk.api.present import * # pylint:disable=W0401,W0614
19
+ from viewo_talk.view import welcome
20
+
21
+
22
+ class Application(flask.Flask):
23
+
24
+ def __init__(self, sources: list = None):
25
+ super().__init__(__name__)
26
+ register_talkme(self, sources=sources)
27
+ self.register()
28
+ self.create_view()
29
+
30
+ def register(self):
31
+ self.register_blueprint(welcome)
32
+
33
+ def create_view(self):
34
+ self.config.setdefault('BOOTSTRAP_SERVE_LOCAL', True)
35
+ # configure extensions
36
+ flask_bootstrap.Bootstrap(app=self)
37
+
38
+
39
+ def register_talkme(app, prefix: str = None, sources: list = None):
40
+ talker = viewo_talk.talk.create(sources=sources)
41
+ app.talker = talker
42
+
43
+ start_talker_before_first_request(app, talker)
44
+
45
+ @app.teardown_appcontext
46
+ def teardown(exception): # pylint:disable=W0613
47
+ talker.stop()
48
+
49
+ @app.before_request
50
+ def talker_push():
51
+ request = viewo_api.request()
52
+ action = viewo_talk.action.fromrequest(request)
53
+ talker.append(action)
54
+
55
+ url_prefix = prefix if prefix else viewo_talk.config.API_PREFIX
56
+ # data API
57
+ app.register_blueprint(viewo_talk.api.api_talk, url_prefix=url_prefix)
58
+
59
+
60
+ def start_talker_before_first_request(app, talker):
61
+ # This method is necessary after upgrading flask which removes
62
+ # before_first_request
63
+ # TODO: VERIFY LATER
64
+ # app.before_first_request(talker.start)
65
+ started = False
66
+ # TODO: INVESTGATE LATER
67
+ @app.before_request
68
+ def start_talker():
69
+ nonlocal started
70
+ if not started:
71
+ talker.start()
72
+ started = True
73
+
74
+
75
+ def create_app(sources: list = None) -> flask.Flask:
76
+ appx = Application(sources=sources)
77
+ return appx
@@ -0,0 +1,16 @@
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 os
11
+
12
+ import configos
13
+
14
+ SECRET_KEY = configos.env('CHANIA_SECRET_KEY', default=os.urandom(64))
15
+
16
+ API_PREFIX = configos.env('CHANIA_API_PREFIX', default='/api/v0')
@@ -0,0 +1,17 @@
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 utilo
11
+
12
+ import viewo_talk.talk
13
+
14
+
15
+ @utilo.cacheme(maxsize=1)
16
+ def talker():
17
+ return viewo_talk.talk.create()
@@ -0,0 +1,8 @@
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
+ # =============================================================================
@@ -0,0 +1,35 @@
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 utilo
11
+
12
+ import viewo_talk.action
13
+
14
+ TITLE, CONTENT = viewo_talk.action.answer_split("""\
15
+ Willkommen auf checkitweg.de
16
+
17
+ Bei Fragen schauen Sie <<hier>>.
18
+ """)
19
+
20
+
21
+ class Welcome(viewo_talk.action.ActionMixin):
22
+
23
+ def __init__(self):
24
+ super().__init__()
25
+ self.done = utilo.Single()
26
+
27
+ def run(self, item: viewo_talk.action.Action):
28
+ user = item.user
29
+ if self.done.contains(user):
30
+ return
31
+ self.send_msg(
32
+ user=user,
33
+ title=TITLE,
34
+ content=CONTENT,
35
+ )
@@ -0,0 +1,30 @@
1
+ const API = '/api/v0'
2
+
3
+ const rpc = function (url, callback, error = undefined) {
4
+ let call = `${API}${url}`
5
+ $.ajax(call, {
6
+ dataType: 'json',
7
+ success: function (response) {
8
+ callback(response)
9
+ },
10
+ error: function (response) {
11
+ if (error != undefined) {
12
+ error()
13
+ } else {
14
+ console.log(`error: ${call}`);
15
+ }
16
+ }
17
+ });
18
+ }
19
+
20
+ const rpc_post = function (url, data, callback) {
21
+ let call = `${API}${url}`
22
+ $.ajax(call, {
23
+ type: 'POST',
24
+ data: data,
25
+ success: function (response) {
26
+ callback(response)
27
+ },
28
+ }
29
+ );
30
+ }
@@ -0,0 +1,68 @@
1
+ const WAITFOR = 5.0
2
+
3
+ const listen = function () {
4
+ rpc(`/talktome`, function (response) {
5
+ let messages = response.messages
6
+ if (messages != undefined) {
7
+ evaluate_messages(messages)
8
+ }
9
+ setTimeout(() => listen(), WAITFOR * 1000);
10
+ })
11
+ }
12
+
13
+ const evaluate_messages = function (messages) {
14
+ for (let message of messages) {
15
+ if (message.name == 'MESSAGE') {
16
+ mbox_show_info(message.title, message.content)
17
+ } else if (message.name == 'QUESTION') {
18
+ mbox_show_question(message.title, message.content, message.index)
19
+ }
20
+ }
21
+ }
22
+
23
+ const mbox_hide = function () {
24
+ $('#mbox').addClass('hidden')
25
+ }
26
+
27
+ const mbox_show_info = function (headline, content) {
28
+ $('#mbox_question').addClass('hidden')
29
+ $('#mbox_headline').text(headline)
30
+ $('#mbox_content').text(content)
31
+ $('#mbox').removeClass('hidden')
32
+ }
33
+
34
+ const mbox_show_question = function (headline, question, index) {
35
+ QUESTION = index
36
+ $('#mbox_question').removeClass('hidden')
37
+ $('#mbox_headline').text(headline)
38
+ $('#mbox_content').text(question)
39
+ $('#mbox').removeClass('hidden')
40
+ }
41
+
42
+ let QUESTION = null
43
+
44
+ const register = function () {
45
+ $(`#mbox_close`).click(function () {
46
+ mbox_hide()
47
+ });
48
+ $(`#mbox_question_yes`).click(function () {
49
+ rpc_post('/talktome', {
50
+ question: QUESTION,
51
+ answer: 1,
52
+ })
53
+ mbox_hide()
54
+ });
55
+ $(`#mbox_question_no`).click(function () {
56
+ rpc_post('/talktome', {
57
+ question: QUESTION,
58
+ answer: 0,
59
+ })
60
+ mbox_hide()
61
+ });
62
+ }
63
+
64
+ $(document).ready(function () {
65
+ register()
66
+ // start after 3 seconds
67
+ setTimeout(() => listen(), 3000);
68
+ })
@@ -0,0 +1,166 @@
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 collections
11
+ import os
12
+ import queue
13
+ import threading
14
+
15
+ import utilo
16
+
17
+ import viewo_talk.action
18
+ import viewo_talk.plan
19
+
20
+
21
+ class Talker:
22
+
23
+ def __init__(self, skip: callable = None):
24
+ self.tasks = []
25
+ self.running = False
26
+ self.todo = queue.Queue()
27
+ self.msg = collections.defaultdict(list)
28
+ self.skip = skip if skip else skipper
29
+
30
+ def append(self, item: viewo_talk.action.Action):
31
+ if self.skip(item.path):
32
+ return
33
+ self.todo.put(item)
34
+
35
+ def answers_pop(self, user: int = None) -> list:
36
+ if self.msg[user]:
37
+ result = list(self.msg[user])
38
+ self.msg[user].clear()
39
+ return result
40
+ return []
41
+
42
+ def consume(self, wait: bool = True) -> bool:
43
+ # use wait:false for unit testing
44
+ if wait:
45
+ job = self.todo.get()
46
+ else:
47
+ try:
48
+ job = self.todo.get_nowait()
49
+ except queue.Empty:
50
+ # nothing todo
51
+ return False
52
+ if job is None:
53
+ # empty job to signal to end processing
54
+ return False
55
+ for task in self.tasks:
56
+ if not route_matches(job.path, task.routes):
57
+ continue
58
+ if isinstance(job, viewo_talk.action.Answer):
59
+ if hasattr(task, 'yes') and job.answer:
60
+ task.yes(job)
61
+ continue
62
+ if hasattr(task, 'no') and not job.answer:
63
+ task.no(job)
64
+ continue
65
+ task.run(job)
66
+ return True
67
+
68
+ def run(self):
69
+ while self.running:
70
+ self.consume()
71
+
72
+ def start(self):
73
+ # TODO: HOW TO TEAR DOWN THIS THREAD? IS IT GONE AFTER SETTING
74
+ # RUNNING=FALSE
75
+ self.running = True
76
+ threading.Thread(target=self.run).start()
77
+
78
+ def stop(self):
79
+ self.running = False
80
+ # ensure that waiting ends
81
+ self.todo.put(None)
82
+
83
+ def send_msg(self, user: str, title: str, content: str = None):
84
+ msg = viewo_talk.action.Message(
85
+ user=user,
86
+ time=utilo.now(),
87
+ title=title,
88
+ content=content,
89
+ )
90
+ self.msg[user].append(msg)
91
+
92
+ def send_question(self, user: str, title: str, content: str = None):
93
+ msg = viewo_talk.action.Question(
94
+ user=user,
95
+ time=utilo.now(),
96
+ title=title,
97
+ content=content,
98
+ )
99
+ self.msg[user].append(msg)
100
+
101
+ def register(self, task):
102
+ self.tasks.append(task)
103
+
104
+
105
+ SKIP = ('GET', f'{viewo_talk.config.API_PREFIX}/talktome')
106
+ ICON = ('GET', '/favicon.ico')
107
+
108
+
109
+ def skipper(item) -> bool:
110
+ if item == SKIP:
111
+ # do not invoke action as a result of message receiving
112
+ return True
113
+ if item == ICON:
114
+ return True
115
+ if item[1].startswith('/static/'):
116
+ return True
117
+ return False
118
+
119
+
120
+ def route_matches(path, routes) -> bool:
121
+ if not routes:
122
+ return True
123
+ mymethod, mypath = path
124
+ for method, url in routes:
125
+ if method != mymethod:
126
+ continue
127
+ if mypath.startswith(url):
128
+ # TODO: IMPROVE THIS
129
+ return True
130
+ return False
131
+
132
+
133
+ def collect(packages) -> list:
134
+ if not utilo.iterable(packages):
135
+ packages = [packages]
136
+ result = []
137
+ for package in packages:
138
+ source = os.path.split(package.__file__)[0]
139
+ for module in utilo.file_list(source, include='py', absolute=True):
140
+ if module.endswith('__init__.py'):
141
+ continue
142
+ loaded = utilo.load_module(module)
143
+ for value in vars(loaded).values():
144
+ if not hasattr(value, 'mro'):
145
+ continue
146
+ if viewo_talk.action.ActionMixin not in value.__mro__:
147
+ continue
148
+ result.append(value)
149
+ return result
150
+
151
+
152
+ def create(sources=None) -> Talker:
153
+ talker = Talker()
154
+ if sources is None:
155
+ sources = [viewo_talk.plan]
156
+ talker = update(talker, sources)
157
+ return talker
158
+
159
+
160
+ def update(talker, sources):
161
+ talker.tasks.clear()
162
+ for ctor in collect(sources):
163
+ constructred = ctor()
164
+ constructred.register(talker)
165
+ talker.register(constructred)
166
+ return talker
@@ -0,0 +1,20 @@
1
+ {% extends "bootstrap/base.html" %}
2
+
3
+ {% block title %}Willkommen - Marhaban{% endblock %}
4
+
5
+ {% block styles %}
6
+ {{ super() }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ {% endblock %}
11
+
12
+ {% block scripts %}
13
+ {{ super() }}
14
+ <script type="text/javascript" src="{{url_for('static', filename='basic.js')}}"></script>
15
+ <script type="text/javascript" src="{{url_for('static', filename='mbox.js')}}"></script>
16
+ {% endblock %}
17
+
18
+ {% block navbar %}
19
+ {% include "mbox.html" %}
20
+ {% endblock %}
@@ -0,0 +1,40 @@
1
+ <style>
2
+ #mbox {
3
+ bottom: 50px;
4
+ left: 30%;
5
+ margin-left: auto;
6
+ margin-right: auto;
7
+ position: fixed;
8
+ border: 2px solid black;
9
+ padding: 30px;
10
+ width: 350px;
11
+ min-height: 200px;
12
+ background-color: chocolate;
13
+ z-index: 1030;
14
+ }
15
+
16
+ #mbox_close {
17
+ position: relative;
18
+ top: -30px;
19
+ right: -30px;
20
+ float: right;
21
+ border-radius: 0px;
22
+ }
23
+
24
+ .hidden {
25
+ visibility: hidden;
26
+ }
27
+
28
+ </style>
29
+
30
+ <div id="mbox" class="hidden">
31
+ <button id="mbox_close" class="btn btn-sm btn-primary">X</button>
32
+ <h3 id="mbox_headline">...</h3>
33
+ <p id="mbox_content">
34
+ ...
35
+ </p>
36
+ <p id="mbox_question" class="hidden">
37
+ <button id="mbox_question_yes" class="btn btn-primary">Ja</button>
38
+ <button id="mbox_question_no" class="btn btn-primary">Nein</button>
39
+ </p>
40
+ </div>
@@ -0,0 +1,17 @@
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 flask
11
+
12
+ welcome = flask.Blueprint('welcome', __name__) # pylint:disable=invalid-name
13
+
14
+
15
+ @welcome.route('/')
16
+ def show_welcome():
17
+ return flask.render_template('base.html')
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: viewo_talk
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_talk
7
+ Project-URL: Repository, https://github.com/anaticulae/viewo_talk
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
+ Requires-Dist: flask-bootstrap<4.0.0.0,>=3.3.7.1
14
+ Requires-Dist: flask<4.0.0,>=3.1.3
15
+ Requires-Dist: utilo<3.0.0,>=2.112.1
16
+ Requires-Dist: viewo_api<2.0.0,>=1.0.1
17
+ Provides-Extra: dev
18
+ Requires-Dist: selenium<5.0.0,>=4.51.0; extra == "dev"
19
+ Requires-Dist: utilotest<2.0.0,>=1.1.1; extra == "dev"
20
+
21
+ # viewo_talk
@@ -0,0 +1,26 @@
1
+ MANIFEST.in
2
+ README
3
+ pyproject.toml
4
+ tests/test_collect.py
5
+ viewo_talk/__init__.py
6
+ viewo_talk/__main__.py
7
+ viewo_talk/action.py
8
+ viewo_talk/app.py
9
+ viewo_talk/config.py
10
+ viewo_talk/main.py
11
+ viewo_talk/talk.py
12
+ viewo_talk/view.py
13
+ viewo_talk.egg-info/PKG-INFO
14
+ viewo_talk.egg-info/SOURCES.txt
15
+ viewo_talk.egg-info/dependency_links.txt
16
+ viewo_talk.egg-info/entry_points.txt
17
+ viewo_talk.egg-info/requires.txt
18
+ viewo_talk.egg-info/top_level.txt
19
+ viewo_talk/api/__init__.py
20
+ viewo_talk/api/present.py
21
+ viewo_talk/plan/__init__.py
22
+ viewo_talk/plan/welcome.py
23
+ viewo_talk/static/basic.js
24
+ viewo_talk/static/mbox.js
25
+ viewo_talk/templates/base.html
26
+ viewo_talk/templates/mbox.html
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ viewo_talk = viewo_talk.cli:main
@@ -0,0 +1,8 @@
1
+ flask-bootstrap<4.0.0.0,>=3.3.7.1
2
+ flask<4.0.0,>=3.1.3
3
+ utilo<3.0.0,>=2.112.1
4
+ viewo_api<2.0.0,>=1.0.1
5
+
6
+ [dev]
7
+ selenium<5.0.0,>=4.51.0
8
+ utilotest<2.0.0,>=1.1.1
@@ -0,0 +1 @@
1
+ viewo_talk