Showing 3 of 5 files from the diff.

@@ -0,0 +1,126 @@
Loading
1 +
import datetime
2 +
import re
3 +
from typing import Callable, Dict, Tuple, Union
4 +
5 +
from karmabot.db import db_session
6 +
from karmabot.db.karma_note import KarmaNote
7 +
from karmabot.db.karma_user import KarmaUser
8 +
9 +
NOTE_CMD_PATTERN = re.compile(r"note\s(\w+)\s?(.*)")
10 +
11 +
12 +
def note(user_id: str, channel: str, text: str) -> Union[None, str]:
13 +
    """Allows the user to store and retrieve simple notes.
14 +
15 +
    - Syntax for adding a note: @karmabot note add <">my note<"> (note message can be in quotes)
16 +
    - Syntax for listing notes: @karmabot note list
17 +
    - Syntax for removing a note: @karmabote note del 1
18 +
19 +
    Each note is stored for the current user only. A user can only list and delete her own notes.
20 +
    """
21 +
    user_id = user_id.strip("<>@")
22 +
23 +
    # retrieve current user
24 +
    user = db_session.create_session().query(KarmaUser).get(user_id)
25 +
    cmd, _ = _parse_note_cmd(text)
26 +
27 +
    note_cmd_fnc = NOTE_COMMANDS.get(cmd, _command_not_found)
28 +
29 +
    return note_cmd_fnc(text, user)
30 +
31 +
32 +
def _add_note(text: str, user: KarmaUser) -> str:
33 +
    """Adds a new note to the database for the given user."""
34 +
    _, note_msg = _parse_note_cmd(text)
35 +
    if not note_msg:
36 +
        return f"Sorry {user.username}, could not find a note in your message."
37 +
38 +
    if _note_exists(note_msg, user):
39 +
        return f"Sorry {user.username}, you already have an identical note."
40 +
41 +
    note = KarmaNote(
42 +
        user_id=user.user_id, timestamp=datetime.datetime.now(), note=note_msg
43 +
    )
44 +
45 +
    session = db_session.create_session()
46 +
    session.add(note)
47 +
    session.commit()
48 +
49 +
    return f"Hey {user.username}, you've just stored a note."
50 +
51 +
52 +
def _del_note(text: str, user: KarmaUser) -> str:
53 +
    """Deletes the note with the given note id."""
54 +
    _, note_id = _parse_note_cmd(text)
55 +
56 +
    if not note_id:
57 +
        return f"Sorry {user.username}, it seems you did not provide a valid id."
58 +
59 +
    session = db_session.create_session()
60 +
    query = session.query(KarmaNote).filter_by(id=note_id, user_id=user.user_id)
61 +
62 +
    row_count = query.delete()
63 +
    session.commit()  # otherwise, the deletion is not performed
64 +
65 +
    if row_count:
66 +
        return f"Hey {user.username}, your note was successfully deleted."
67 +
68 +
    return (
69 +
        f"Sorry {user.username}, something went wrong, no record was deleted. "
70 +
        f"Please ask an admin..."
71 +
    )
72 +
73 +
74 +
def _list_notes(text: str, user: KarmaUser) -> str:
75 +
    """List all notes for a given user."""
76 +
    notes = _get_notes_for_user(user)
77 +
78 +
    if not notes:
79 +
        return (
80 +
            f"Sorry {user.username}, you don't have any notes so far! "
81 +
            f"Just start adding notes via the 'note add' command."
82 +
        )
83 +
84 +
    msg = "\n".join(f"{i+1}. note {str(note)}" for i, note in enumerate(notes))
85 +
86 +
    return msg
87 +
88 +
89 +
def _command_not_found(text: str, user: KarmaUser) -> str:
90 +
    return (
91 +
        f"Sorry {user.username}, your note command was not recognized. "
92 +
        f"You can use {', '.join(NOTE_COMMANDS.keys())}."
93 +
    )
94 +
95 +
96 +
def _parse_note_cmd(text: str) -> Tuple[str, str]:
97 +
    note_cmd = ("", "")
98 +
99 +
    match = NOTE_CMD_PATTERN.search(text)
100 +
    if match:
101 +
        note_cmd = match.group(1).strip(), match.group(2).strip("\"'")
102 +
103 +
    return note_cmd
104 +
105 +
106 +
def _get_notes_for_user(user: KarmaUser) -> list:
107 +
    return (
108 +
        db_session.create_session()
109 +
        .query(KarmaNote)
110 +
        .filter_by(user_id=user.user_id)
111 +
        .all()
112 +
    )
113 +
114 +
115 +
def _note_exists(msg: str, user: KarmaUser) -> bool:
116 +
    session = db_session.create_session()
117 +
    q = session.query(KarmaNote).filter_by(note=msg, user_id=user.user_id)
118 +
119 +
    return session.query(q.exists()).scalar()  # returns True or False
120 +
121 +
122 +
NOTE_COMMANDS: Dict[str, Callable] = {
123 +
    "add": _add_note,
124 +
    "del": _del_note,
125 +
    "list": _list_notes,
126 +
}

@@ -0,0 +1,32 @@
Loading
1 +
import datetime
2 +
3 +
import sqlalchemy as sa
4 +
5 +
from karmabot.db.modelbase import SqlAlchemyBase
6 +
7 +
8 +
class KarmaNote(SqlAlchemyBase):
9 +
    """ Models a simple note system in the DB """
10 +
11 +
    __tablename__ = "karma_note"
12 +
13 +
    id: int = sa.Column(
14 +
        sa.BigInteger().with_variant(sa.Integer, "sqlite"),
15 +
        primary_key=True,
16 +
        autoincrement=True,
17 +
    )
18 +
    user_id = sa.Column(sa.String, sa.ForeignKey("karma_user.user_id"), nullable=False)
19 +
    timestamp = sa.Column(sa.DateTime, default=datetime.datetime.now, nullable=False)
20 +
    note = sa.Column(sa.String)
21 +
22 +
    def __repr__(self):
23 +
        return (
24 +
            f"[KarmaNote] ID: {self.id} | {self.user_id} -> "
25 +
            f"{self.timestamp} | Note: {self.note}"
26 +
        )
27 +
28 +
    def __str__(self):
29 +
        return (
30 +
            f"(ID: {self.id}) from {self.timestamp.strftime('%Y-%m-%d, %H:%M')}: "
31 +
            f"{self.note}."
32 +
        )

@@ -12,6 +12,7 @@
Loading
12 12
from karmabot.commands.feed import get_pybites_last_entries
13 13
from karmabot.commands.help import create_commands_table
14 14
from karmabot.commands.joke import joke
15 +
from karmabot.commands.note import note
15 16
from karmabot.commands.score import get_karma, top_karma
16 17
from karmabot.commands.tip import get_random_tip
17 18
from karmabot.commands.topchannels import get_recommended_channels
@@ -30,22 +31,24 @@
Loading
30 31
AUTOMATED_COMMANDS = {"welcome": welcome_user}  # not manual
31 32
ADMIN_BOT_COMMANDS = {"top_karma": top_karma}
32 33
PUBLIC_BOT_COMMANDS = {
33 -
    "age": pybites_age,
34 34
    "add": add_command,
35 +
    "age": pybites_age,
35 36
    "help": create_commands_table,
37 +
    "joke": joke,
38 +
    "note": note,
36 39
    "tip": get_random_tip,
37 40
    "topchannels": get_recommended_channels,
38 -
    "joke": joke,
39 41
}
40 42
PRIVATE_BOT_COMMANDS = {
41 -
    "feed": get_pybites_last_entries,
42 43
    "doc": doc_command,
44 +
    "feed": get_pybites_last_entries,
43 45
    "help": create_commands_table,
46 +
    "joke": joke,
47 +
    "note": note,
44 48
    "karma": get_karma,
45 49
    "topchannels": get_recommended_channels,
46 -
    "updateusername": update_username,
47 50
    "username": get_user_name,
48 -
    "joke": joke,
51 +
    "updateusername": update_username,
49 52
}
50 53
51 54
Message = namedtuple("Message", "user_id channel_id text")
Files Coverage
src/karmabot 55.35%
Project Totals (23 files) 55.35%

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading