move data logic to plugins, split models from controller
This commit is contained in:
parent
52aeb1128f
commit
60293152d6
@ -48,6 +48,7 @@ class Config():
|
|||||||
def __getattr__(self, __name: str):
|
def __getattr__(self, __name: str):
|
||||||
return self.config[__name]
|
return self.config[__name]
|
||||||
|
|
||||||
|
# Format the config for display
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
repr = []
|
repr = []
|
||||||
repr.append(f"app_name: {self.app_name}\r\n")
|
repr.append(f"app_name: {self.app_name}\r\n")
|
||||||
|
|||||||
@ -16,11 +16,8 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import sqlalchemy.exc
|
|
||||||
|
|
||||||
import rsbbs
|
import rsbbs
|
||||||
from rsbbs.config import Config
|
from rsbbs.config import Config
|
||||||
from rsbbs.controller import Controller
|
from rsbbs.controller import Controller
|
||||||
@ -134,22 +131,6 @@ class Console():
|
|||||||
f"{datetime_: <{11}} "
|
f"{datetime_: <{11}} "
|
||||||
f"{message.Message.subject}")
|
f"{message.Message.subject}")
|
||||||
|
|
||||||
#
|
|
||||||
# Command functions
|
|
||||||
#
|
|
||||||
|
|
||||||
def send_private(self, args):
|
|
||||||
self.send(args, is_private=True)
|
|
||||||
"""Send a message visible only to the recipient callsign.
|
|
||||||
|
|
||||||
Required arguments:
|
|
||||||
callsign -- the recipient's callsign
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
subject -- message subject
|
|
||||||
message -- the message itself
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Main input loop
|
# Main input loop
|
||||||
#
|
#
|
||||||
|
|||||||
@ -16,42 +16,20 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import subprocess
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
from datetime import datetime, timezone
|
|
||||||
|
|
||||||
from sqlalchemy import Boolean, DateTime, String
|
|
||||||
from sqlalchemy import create_engine, delete, select, or_
|
|
||||||
|
|
||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, Session
|
|
||||||
from sqlalchemy.orm import mapped_column
|
|
||||||
|
|
||||||
from rsbbs.config import Config
|
from rsbbs.config import Config
|
||||||
|
from rsbbs.models import Base
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Message(Base):
|
|
||||||
__tablename__ = 'message'
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
sender: Mapped[str] = mapped_column(String)
|
|
||||||
recipient: Mapped[str] = mapped_column(String)
|
|
||||||
subject: Mapped[str] = mapped_column(String)
|
|
||||||
message: Mapped[str] = mapped_column(String)
|
|
||||||
datetime: Mapped[DateTime] = mapped_column(
|
|
||||||
DateTime, default=datetime.now(timezone.utc))
|
|
||||||
is_private: Mapped[bool] = mapped_column(Boolean)
|
|
||||||
|
|
||||||
|
|
||||||
class Controller():
|
class Controller():
|
||||||
|
|
||||||
def __init__(self, config: Config):
|
def __init__(self, config: Config) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
self._init_datastore()
|
self._init_datastore()
|
||||||
|
|
||||||
def _init_datastore(self):
|
def _init_datastore(self) -> None:
|
||||||
"""Create a connection to the sqlite3 database.
|
"""Create a connection to the sqlite3 database.
|
||||||
|
|
||||||
The default location is the system-specific user-level data directory.
|
The default location is the system-specific user-level data directory.
|
||||||
@ -64,103 +42,5 @@ class Controller():
|
|||||||
# Create the database schema if none exists
|
# Create the database schema if none exists
|
||||||
Base.metadata.create_all(self.engine)
|
Base.metadata.create_all(self.engine)
|
||||||
|
|
||||||
def delete(self, args):
|
def session(self) -> Session:
|
||||||
"""Delete a message.
|
return Session(self.engine)
|
||||||
|
|
||||||
Arguments:
|
|
||||||
number -- the message number to delete
|
|
||||||
"""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
message = session.get(Message, args.number)
|
|
||||||
session.delete(message)
|
|
||||||
session.commit()
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def delete_mine(self, args):
|
|
||||||
"""Delete all messages addressed to the calling station's callsign."""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
statement = delete(Message).where(
|
|
||||||
Message.recipient == self.config.calling_station
|
|
||||||
).returning(Message)
|
|
||||||
result = session.execute(
|
|
||||||
statement,
|
|
||||||
execution_options={"prebuffer_rows": True})
|
|
||||||
session.commit()
|
|
||||||
return result
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def list(self, args):
|
|
||||||
"""List all messages."""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
# Using or_ and is_ etc. to distinguish from python operators
|
|
||||||
statement = select(Message).where(
|
|
||||||
or_(
|
|
||||||
(Message.is_private.is_(False)),
|
|
||||||
(Message.recipient.__eq__(
|
|
||||||
self.config.calling_station)))
|
|
||||||
)
|
|
||||||
result = session.execute(
|
|
||||||
statement,
|
|
||||||
execution_options={"prebuffer_rows": True})
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
return result
|
|
||||||
|
|
||||||
def list_mine(self, args):
|
|
||||||
"""List only messages addressed to the calling station's callsign,
|
|
||||||
including public and private messages.
|
|
||||||
"""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
statement = select(Message).where(
|
|
||||||
Message.recipient == self.config.calling_station)
|
|
||||||
result = session.execute(
|
|
||||||
statement,
|
|
||||||
execution_options={"prebuffer_rows": True})
|
|
||||||
return result
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def read(self, args):
|
|
||||||
"""Read a message.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
number -- the message number to read
|
|
||||||
"""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
statement = select(Message).where(Message.id == args.number)
|
|
||||||
result = session.execute(statement).one()
|
|
||||||
return result
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def send(self, args, is_private=False):
|
|
||||||
"""Create a new message addressed to another callsign.
|
|
||||||
|
|
||||||
Required arguments:
|
|
||||||
callsign -- the recipient's callsign
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
subject -- message subject
|
|
||||||
message -- the message itself
|
|
||||||
"""
|
|
||||||
with Session(self.engine) as session:
|
|
||||||
try:
|
|
||||||
session.add(Message(
|
|
||||||
sender=self.config.calling_station.upper(),
|
|
||||||
recipient=args.callsign.upper(),
|
|
||||||
subject=args.subject,
|
|
||||||
message=args.message,
|
|
||||||
is_private=is_private
|
|
||||||
))
|
|
||||||
session.commit()
|
|
||||||
return {}
|
|
||||||
except Exception:
|
|
||||||
session.rollback()
|
|
||||||
raise
|
|
||||||
|
|||||||
40
rsbbs/models.py
Normal file
40
rsbbs/models.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Really Simple BBS - a really simple BBS for ax.25 packet radio.
|
||||||
|
# Copyright (C) 2023 John Burwell <john@atatdotdot.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from sqlalchemy import Boolean, DateTime, String
|
||||||
|
|
||||||
|
from sqlalchemy.orm import DeclarativeBase, Mapped
|
||||||
|
from sqlalchemy.orm import mapped_column
|
||||||
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Message(Base):
|
||||||
|
__tablename__ = 'message'
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
sender: Mapped[str] = mapped_column(String)
|
||||||
|
recipient: Mapped[str] = mapped_column(String)
|
||||||
|
subject: Mapped[str] = mapped_column(String)
|
||||||
|
message: Mapped[str] = mapped_column(String)
|
||||||
|
datetime: Mapped[DateTime] = mapped_column(
|
||||||
|
DateTime, default=datetime.now(timezone.utc))
|
||||||
|
is_private: Mapped[bool] = mapped_column(Boolean)
|
||||||
@ -22,20 +22,20 @@ from rsbbs.parser import Parser
|
|||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='bye',
|
name='bye',
|
||||||
aliases=['b', 'q'],
|
aliases=['b', 'q'],
|
||||||
help='Sign off and disconnect')
|
help='Sign off and disconnect')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args) -> None:
|
||||||
"""Disconnect and exit."""
|
"""Disconnect and exit."""
|
||||||
self.api.write_output("Bye!")
|
self.api.write_output("Bye!")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|||||||
@ -16,19 +16,23 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
import sqlalchemy.exc
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='delete',
|
name='delete',
|
||||||
aliases=['d', 'k'],
|
aliases=['d', 'k'],
|
||||||
@ -37,11 +41,23 @@ class Plugin():
|
|||||||
help='The number of the message to delete')
|
help='The number of the message to delete')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def delete(self, number) -> None:
|
||||||
"""Delete a message specified by ID number."""
|
with self.api.controller.session() as session:
|
||||||
if args.number:
|
|
||||||
try:
|
try:
|
||||||
self.api.controller.delete(args)
|
message = session.get(Message, number)
|
||||||
self.api.write_output(f"Deleted message #{args.number}")
|
session.delete(message)
|
||||||
except Exception as e:
|
session.commit()
|
||||||
|
self.api.write_output(f"Deleted message #{number}")
|
||||||
|
except sqlalchemy.exc.NoResultFound:
|
||||||
self.api.write_output(f"Message not found.")
|
self.api.write_output(f"Message not found.")
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
|
"""Delete a message.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
number -- the message number to delete
|
||||||
|
"""
|
||||||
|
if args.number:
|
||||||
|
self.delete(args.number)
|
||||||
|
|||||||
@ -16,34 +16,38 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='deletem',
|
name='deletem',
|
||||||
aliases=['dm', 'km'],
|
aliases=['dm', 'km'],
|
||||||
help='Delete all messages addressed to you')
|
help='Delete all messages addressed to you')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def delete_mine(self) -> None:
|
||||||
"""Delete all messages addressed to the calling station's callsign."""
|
with self.api.controller.session() as session:
|
||||||
response = self.api.read_line(
|
|
||||||
"Delete all messages addressed to you? Y/N:")
|
|
||||||
if response.lower() != "y":
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
result = self.api.controller.delete_mine(args)
|
statement = sqlalchemy.delete(Message).where(
|
||||||
|
Message.recipient == self.api.config.calling_station
|
||||||
|
).returning(Message)
|
||||||
|
result = session.execute(
|
||||||
|
statement,
|
||||||
|
execution_options={"prebuffer_rows": True})
|
||||||
|
session.commit()
|
||||||
messages = result.all()
|
messages = result.all()
|
||||||
count = len(messages)
|
count = len(messages)
|
||||||
if count > 0:
|
if count > 0:
|
||||||
@ -52,3 +56,10 @@ class Plugin():
|
|||||||
self.api.write_output(f"No messages to delete.")
|
self.api.write_output(f"No messages to delete.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.api.write_output(f"Unable to delete messages: {e}")
|
self.api.write_output(f"Unable to delete messages: {e}")
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
|
"""Delete all messages addressed to the calling station's callsign."""
|
||||||
|
response = self.api.read_line(
|
||||||
|
"Delete all messages addressed to you? Y/N:")
|
||||||
|
if response.lower() == "y":
|
||||||
|
self.delete_mine()
|
||||||
|
|||||||
@ -24,20 +24,20 @@ from rsbbs.parser import Parser
|
|||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='heard',
|
name='heard',
|
||||||
aliases=['j'],
|
aliases=['j'],
|
||||||
help='Show heard stations log')
|
help='Show heard stations log')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args) -> None:
|
||||||
"""Show a log of stations that have been heard by this station,
|
"""Show a log of stations that have been heard by this station,
|
||||||
also known as the 'mheard' (linux) or 'jheard' (KPC, etc.) log.
|
also known as the 'mheard' (linux) or 'jheard' (KPC, etc.) log.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -22,20 +22,20 @@ from rsbbs.parser import Parser
|
|||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='help',
|
name='help',
|
||||||
aliases=['h', '?'],
|
aliases=['h', '?'],
|
||||||
help='Show help')
|
help='Show help')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args) -> None:
|
||||||
"""Show a log of stations that have been heard by this station,
|
"""Show a log of stations that have been heard by this station,
|
||||||
also known as the 'mheard' (linux) or 'jheard' (KPC, etc.) log.
|
also known as the 'mheard' (linux) or 'jheard' (KPC, etc.) log.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -16,26 +16,47 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='list',
|
name='list',
|
||||||
aliases=['l'],
|
aliases=['l'],
|
||||||
help='List all available messages')
|
help='List all available messages')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def list(self, args) -> sqlalchemy.ChunkedIteratorResult:
|
||||||
|
"""List all messages."""
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
# Using or_ and is_ etc. to distinguish from python operators
|
||||||
|
statement = sqlalchemy.select(Message).where(
|
||||||
|
sqlalchemy.or_(
|
||||||
|
(Message.is_private.is_(False)),
|
||||||
|
(Message.recipient.__eq__(
|
||||||
|
self.api.config.calling_station)))
|
||||||
|
)
|
||||||
|
result = session.execute(
|
||||||
|
statement,
|
||||||
|
execution_options={"prebuffer_rows": True})
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
return result
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
"""List all public messages and messages private to the caller."""
|
"""List all public messages and messages private to the caller."""
|
||||||
result = self.api.controller.list(args)
|
result = self.list(args)
|
||||||
self.api.print_message_list(result)
|
self.api.print_message_list(result)
|
||||||
|
|||||||
@ -16,28 +16,43 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='listm',
|
name='listm',
|
||||||
aliases=['lm'],
|
aliases=['lm'],
|
||||||
help='List only messages addressed to you')
|
help='List only messages addressed to you')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
|
def list_mine(self, args) -> sqlalchemy.ChunkedIteratorResult:
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
statement = sqlalchemy.select(Message).where(
|
||||||
|
Message.recipient == self.api.config.calling_station)
|
||||||
|
result = session.execute(
|
||||||
|
statement,
|
||||||
|
execution_options={"prebuffer_rows": True})
|
||||||
|
return result
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args):
|
||||||
"""List only messages addressed to the calling station's callsign,
|
"""List only messages addressed to the calling station's callsign,
|
||||||
including public and private messages.
|
including public and private messages.
|
||||||
"""
|
"""
|
||||||
result = self.api.controller.list_mine(args)
|
result = self.list_mine(args)
|
||||||
self.api.print_message_list(result)
|
self.api.print_message_list(result)
|
||||||
|
|||||||
@ -17,20 +17,22 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
import sqlalchemy.exc
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='read',
|
name='read',
|
||||||
aliases=['r'],
|
aliases=['r'],
|
||||||
@ -38,17 +40,23 @@ class Plugin():
|
|||||||
subparser.add_argument('number', help='Message number to read')
|
subparser.add_argument('number', help='Message number to read')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def read_message(self, number) -> None:
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
statement = sqlalchemy.select(Message).where(
|
||||||
|
Message.id == number)
|
||||||
|
result = session.execute(statement).one()
|
||||||
|
self.api.print_message(result)
|
||||||
|
except sqlalchemy.exc.NoResultFound:
|
||||||
|
self.api.write_output(f"Message not found.")
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
"""Read a message.
|
"""Read a message.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
number -- the message number to read
|
number -- the message number to read
|
||||||
"""
|
"""
|
||||||
if args.number:
|
if args.number:
|
||||||
try:
|
self.read_message(args.number)
|
||||||
result = self.api.controller.read(args)
|
|
||||||
self.api.print_message(result)
|
|
||||||
except sqlalchemy.exc.NoResultFound:
|
|
||||||
self.api.write_output(f"Message not found.")
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|||||||
@ -19,28 +19,41 @@
|
|||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='readm',
|
name='readm',
|
||||||
aliases=['rm'],
|
aliases=['rm'],
|
||||||
help='Read all messages addressed to you')
|
help='Read all messages addressed to you')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def list_mine(self, args) -> sqlalchemy.ChunkedIteratorResult:
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
statement = sqlalchemy.select(Message).where(
|
||||||
|
Message.recipient == self.api.config.calling_station)
|
||||||
|
result = session.execute(
|
||||||
|
statement,
|
||||||
|
execution_options={"prebuffer_rows": True})
|
||||||
|
return result
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
"""Read all messages addressed to the calling station's callsign,
|
"""Read all messages addressed to the calling station's callsign,
|
||||||
in sequence."""
|
in sequence."""
|
||||||
result = self.api.controller.list_mine(args)
|
result = self.list_mine(args)
|
||||||
messages = result.all()
|
messages = result.all()
|
||||||
count = len(messages)
|
count = len(messages)
|
||||||
if count > 0:
|
if count > 0:
|
||||||
|
|||||||
@ -16,21 +16,20 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sqlalchemy
|
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='send',
|
name='send',
|
||||||
aliases=['s'],
|
aliases=['s'],
|
||||||
@ -40,7 +39,22 @@ class Plugin():
|
|||||||
subparser.add_argument('--message', help='Message')
|
subparser.add_argument('--message', help='Message')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def send(self, args, is_private=False) -> None:
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
session.add(Message(
|
||||||
|
sender=self.api.config.calling_station.upper(),
|
||||||
|
recipient=args.callsign.upper(),
|
||||||
|
subject=args.subject,
|
||||||
|
message=args.message,
|
||||||
|
is_private=is_private
|
||||||
|
))
|
||||||
|
session.commit()
|
||||||
|
except Exception:
|
||||||
|
session.rollback()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
"""Create a new message addressed to another callsign.
|
"""Create a new message addressed to another callsign.
|
||||||
|
|
||||||
Required arguments:
|
Required arguments:
|
||||||
@ -58,6 +72,6 @@ class Plugin():
|
|||||||
args.message = self.api.read_multiline(
|
args.message = self.api.read_multiline(
|
||||||
"Message - end with /ex on a single line:")
|
"Message - end with /ex on a single line:")
|
||||||
try:
|
try:
|
||||||
self.api.controller.send(args, is_private=False)
|
self.send(args)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|||||||
@ -16,21 +16,20 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sqlalchemy
|
|
||||||
|
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
|
from rsbbs.models import Message
|
||||||
from rsbbs.parser import Parser
|
from rsbbs.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class Plugin():
|
class Plugin():
|
||||||
|
|
||||||
def __init__(self, api: Console):
|
def __init__(self, api: Console) -> None:
|
||||||
self.api = api
|
self.api = api
|
||||||
self.init_parser(api.parser)
|
self.init_parser(api.parser)
|
||||||
if api.config.debug:
|
if api.config.debug:
|
||||||
print(f"Plugin {__name__} loaded")
|
print(f"Plugin {__name__} loaded")
|
||||||
|
|
||||||
def init_parser(self, parser: Parser):
|
def init_parser(self, parser: Parser) -> None:
|
||||||
subparser = parser.subparsers.add_parser(
|
subparser = parser.subparsers.add_parser(
|
||||||
name='sendp',
|
name='sendp',
|
||||||
aliases=['sp'],
|
aliases=['sp'],
|
||||||
@ -40,7 +39,22 @@ class Plugin():
|
|||||||
subparser.add_argument('--message', help='Message')
|
subparser.add_argument('--message', help='Message')
|
||||||
subparser.set_defaults(func=self.run)
|
subparser.set_defaults(func=self.run)
|
||||||
|
|
||||||
def run(self, args):
|
def send(self, args, is_private=False) -> None:
|
||||||
|
with self.api.controller.session() as session:
|
||||||
|
try:
|
||||||
|
session.add(Message(
|
||||||
|
sender=self.api.config.calling_station.upper(),
|
||||||
|
recipient=args.callsign.upper(),
|
||||||
|
subject=args.subject,
|
||||||
|
message=args.message,
|
||||||
|
is_private=is_private
|
||||||
|
))
|
||||||
|
session.commit()
|
||||||
|
except Exception:
|
||||||
|
session.rollback()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def run(self, args) -> None:
|
||||||
"""Create a new message addressed to another callsign.
|
"""Create a new message addressed to another callsign.
|
||||||
|
|
||||||
Required arguments:
|
Required arguments:
|
||||||
@ -58,6 +72,6 @@ class Plugin():
|
|||||||
args.message = self.api.read_multiline(
|
args.message = self.api.read_multiline(
|
||||||
"Message - end with /ex on a single line:")
|
"Message - end with /ex on a single line:")
|
||||||
try:
|
try:
|
||||||
self.api.controller.send(args, is_private=True)
|
self.send(args, is_private=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|||||||
@ -23,7 +23,6 @@ from rsbbs import __version__
|
|||||||
from rsbbs.config import Config
|
from rsbbs.config import Config
|
||||||
from rsbbs.console import Console
|
from rsbbs.console import Console
|
||||||
from rsbbs.controller import Controller
|
from rsbbs.controller import Controller
|
||||||
from rsbbs.parser import Parser
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user