From a25c6819ff0ac3b074c24329b0197253fcf8f652 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Fri, 6 Jan 2023 20:42:56 +0000 Subject: [PATCH] Updating accounts and hashtags in db from Mastodon works --- app/config.py | 15 +- app/helpers.py | 16 + app/models.py | 47 +++ app/ui/double-left.png | Bin 0 -> 7580 bytes app/ui/double-right.png | Bin 0 -> 7848 bytes app/ui/main_window.ui | 603 ++++++++++++++++++++++++--------- app/ui/main_window_original.ui | 281 +++++++++++++++ app/ui/main_window_ui.py | 188 ++++++---- app/ui/urma.qrc | 2 + app/urma.py | 209 ++++++++++-- 10 files changed, 1117 insertions(+), 244 deletions(-) create mode 100644 app/ui/double-left.png create mode 100644 app/ui/double-right.png create mode 100644 app/ui/main_window_original.ui diff --git a/app/config.py b/app/config.py index 3e8a0ed..4971f9e 100644 --- a/app/config.py +++ b/app/config.py @@ -8,14 +8,13 @@ class Config(object): # DEBUG_FUNCTIONS: List[Optional[str]] = [] # DEBUG_MODULES: List[Optional[str]] = ['dbconfig'] DISPLAY_SQL = False - # ERRORS_FROM = ['noreply@midnighthax.com'] - # ERRORS_TO = ['kae@midnighthax.com'] + ERRORS_FROM = ['noreply@midnighthax.com'] + ERRORS_TO = ['kae@midnighthax.com'] LOG_LEVEL_STDERR = logging.ERROR LOG_LEVEL_SYSLOG = logging.DEBUG LOG_NAME = "urma" - # MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') - # MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25) - # MAIL_SERVER = os.environ.get('MAIL_SERVER') or - # "woodlands.midnighthax.com" - # MAIL_USERNAME = os.environ.get('MAIL_USERNAME') - # MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None + MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') + MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25) + MAIL_SERVER = os.environ.get('MAIL_SERVER') or "woodlands.midnighthax.com" + MAIL_USERNAME = os.environ.get('MAIL_USERNAME') + MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None diff --git a/app/helpers.py b/app/helpers.py index 74f5bf9..b399fc2 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -7,6 +7,8 @@ from email.message import EmailMessage from config import Config from log import log +from typing import Any, List + def ask_yes_no(title: str, question: str) -> bool: """Ask question; return True for yes, False for no""" @@ -16,6 +18,20 @@ def ask_yes_no(title: str, question: str) -> bool: return button_reply == QMessageBox.Yes +def index_ojects_by_parameter(object_list: List, param: Any): + """ + Create a dictionary from passed list where each list entry is keyed + by passed param + n + """ + + results = {} + for obj in object_list: + results[getattr(obj, param)] = obj + + return results + + def send_mail(to_addr, from_addr, subj, body): # From https://docs.python.org/3/library/email.examples.html diff --git a/app/models.py b/app/models.py index 1f2ee16..98cd6eb 100644 --- a/app/models.py +++ b/app/models.py @@ -4,6 +4,8 @@ import os.path from dbconfig import Session, scoped_session +from typing import List + from sqlalchemy import ( Boolean, Column, @@ -56,6 +58,21 @@ class Accounts(Base): session.add(self) session.commit() + @classmethod + def get_followed(cls, session: Session) -> List["Accounts"]: + """ + Return a list of account objects that we follow + """ + + records = ( + session.execute( + select(cls) + .where(cls.followed.is_(True)) + ).scalars().all() + ) + + return records + @classmethod def get_or_create(cls, session: Session, account_id: str) -> "Accounts": """ @@ -148,6 +165,21 @@ class Hashtags(Base): session.add(self) session.commit() + @classmethod + def get_followed(cls, session: Session) -> List["Hashtags"]: + """ + Return a list of hashtags objects that we follow + """ + + records = ( + session.execute( + select(cls) + .where(cls.followed.is_(True)) + ).scalars().all() + ) + + return records + @classmethod def get_or_create(cls, session: Session, name: str, url: str) -> "Hashtags": @@ -218,6 +250,21 @@ class Posts(Base): return rec + @classmethod + def get_unrated_posts(cls, session: Session) -> List["Posts"]: + """ + Return a list of Posts object that have not been rated + """ + + records = ( + session.execute( + select(cls) + .where(cls.rating.is_(None)) + ).scalars().all() + ) + + return records + class PostTags(Base): __tablename__ = 'post_tags' diff --git a/app/ui/double-left.png b/app/ui/double-left.png new file mode 100644 index 0000000000000000000000000000000000000000..781a11392f06bb4e91162b50b418a5025c35a4d5 GIT binary patch literal 7580 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 literal 0 HcmV?d00001 diff --git a/app/ui/double-right.png b/app/ui/double-right.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f38b6606cf8aad6afe08b5cf0ca317db7b0504 GIT binary patch literal 7848 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 literal 0 HcmV?d00001 diff --git a/app/ui/main_window.ui b/app/ui/main_window.ui index 1ac1ed6..1f85129 100644 --- a/app/ui/main_window.ui +++ b/app/ui/main_window.ui @@ -6,181 +6,468 @@ 0 0 - 800 - 574 + 709 + 1100 - Urma + MainWindow + + + false + + + background-color: #232834; - - - - - Username: - - - - - - - - - - - - - - - - - - - - - - - - - :/buttons/icons8-next-page-48.png:/buttons/icons8-next-page-48.png - - - - 48 - 48 - - - - - - - - Hashtags: - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + 10 + 90 + 351 + 681 + + + + + 341 + 181 + + + + background-color: rgb(154, 153, 150); border-radius: 10px; + + + + QFrame::StyledPanel + + + QAbstractScrollArea::AdjustIgnored + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:8px; margin-bottom:8px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - - - - - - - :/buttons/icons8-prev-page-48.png:/buttons/icons8-prev-page-48.png - - - - 48 - 48 - - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ffffff;">The magic of adulthood is in finding new and interesting ways of being disappointed </span><span style=" color:#5e5c64;">&lt;a href=&quot;xxx&quot;&gt;thisn&lt;/a&gt; </span><a href="https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md"><span style=" text-decoration: underline; color:#0000ff;">https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md <br /></span></a><a href="https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md"><span style=" text-decoration: underline; color:#000000;">and some black text</span></a></p></body></html> + + + + + + 20 + 770 + 351 + 191 + + + + + 0 + 181 + + + + QFrame::StyledPanel + + + + + + + + + 370 + 90 + 331 + 871 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - - - - 72 - 75 - true - - - - 2 - - - urma - - - - - - - Dislike - - - - :/buttons/red-cross.png:/buttons/red-cross.png - - - - 48 - 48 - - - - - - - - Not sure - - - - :/buttons/dont-know-woman.png:/buttons/dont-know-woman.png - - - - 48 - 48 - - - - - - - - Like - - - - :/buttons/green-tick.png:/buttons/green-tick.png - - - - 48 - 48 - - - - - +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#f6f5f4;">#notthis<br />#orthis</span><br /><span style=" color:#8ae234;">#butthis</span><br /><span style=" color:#f6f5f4;">#notthis</span><br /><span style=" color:#8ae234;">#yes</span><br /><span style=" color:#8ae234;">#yes</span><br /><span style=" color:#ffffff;">#no</span></p></body></html> + + + + + + 10 + 0 + 361 + 31 + + + + + 0 + 29 + + + + + 16777215 + 29 + + + + + 13 + + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#5e5c64;">Boosted by</span><span style=" color:#f6f5f4;"> Jon</span> <span style=" color:#8ae234;">Baker</span></p></body></html> + + + + + + 10 + 980 + 701 + 63 + + + + + + + + 61 + 61 + + + + + 61 + 61 + + + + + + + + :/buttons/double-left.png:/buttons/double-left.png + + + + 48 + 48 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 61 + 61 + + + + + 61 + 61 + + + + + + + + :/buttons/icons8-prev-page-48.png:/buttons/icons8-prev-page-48.png + + + + 48 + 48 + + + + + + + + + 106 + 61 + + + + + 106 + 61 + + + + + + + + :/buttons/red-cross.png:/buttons/red-cross.png + + + + 48 + 48 + + + + + + + + + 106 + 61 + + + + + 106 + 61 + + + + + + + + :/buttons/dont-know-woman.png:/buttons/dont-know-woman.png + + + + 48 + 48 + + + + + + + + + 106 + 61 + + + + + 106 + 61 + + + + + + + + :/buttons/green-tick.png:/buttons/green-tick.png + + + + 48 + 48 + + + + + + + + + 61 + 61 + + + + + 61 + 61 + + + + + + + + :/buttons/icons8-next-page-48.png:/buttons/icons8-next-page-48.png + + + + 48 + 48 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 61 + 61 + + + + + 61 + 61 + + + + + + + + :/buttons/double-right.png:/buttons/double-right.png + + + + 48 + 48 + + + + + + + + + + 10 + 60 + 361 + 29 + + + + + 0 + 29 + + + + + 16777215 + 29 + + + + color: rgb(119, 118, 123); + + + @JonBaker@mastodon.xyz + + + + + + 10 + 30 + 361 + 29 + + + + + 0 + 29 + + + + + 16777215 + 29 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#f6f5f4;">Jon</span> <span style=" color:#8ae234;">Baker</span></p></body></html> + + + + + + 366 + 90 + 2 + 871 + + + + background-color: rgb(119, 118, 123); + + + Qt::Vertical + + 0 0 - 800 + 709 26 diff --git a/app/ui/main_window_original.ui b/app/ui/main_window_original.ui new file mode 100644 index 0000000..39ab83a --- /dev/null +++ b/app/ui/main_window_original.ui @@ -0,0 +1,281 @@ + + + MainWindow + + + + 0 + 0 + 800 + 533 + + + + Urma + + + + + + 9 + 9 + 93 + 21 + + + + Username: + + + + + + 140 + 9 + 16 + 20 + + + + + + + + + + 731 + 9 + 60 + 54 + + + + + + + + :/buttons/icons8-next-page-48.png:/buttons/icons8-next-page-48.png + + + + 48 + 48 + + + + + + + 20 + 90 + 86 + 21 + + + + Hashtags: + + + + + + 20 + 121 + 256 + 251 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:8px; margin-bottom:8px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + 731 + 183 + 60 + 54 + + + + + + + + :/buttons/icons8-prev-page-48.png:/buttons/icons8-prev-page-48.png + + + + 48 + 48 + + + + + + false + + + + 10 + 40 + 81 + 21 + + + + + 75 + true + + + + color rgb(200, 0, 3); + + + Boosted + + + + + + 10 + 358 + 281 + 113 + + + + + 72 + 75 + true + + + + 2 + + + urma + + + + + + 290 + 10 + 358 + 441 + + + + + + + + 0 + 160 + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + + Dislike + + + + :/buttons/red-cross.png:/buttons/red-cross.png + + + + 48 + 48 + + + + + + + + Not sure + + + + :/buttons/dont-know-woman.png:/buttons/dont-know-woman.png + + + + 48 + 48 + + + + + + + + Like + + + + :/buttons/green-tick.png:/buttons/green-tick.png + + + + 48 + 48 + + + + + + + + + + + + + 0 + 0 + 800 + 26 + + + + + + + + + + diff --git a/app/ui/main_window_ui.py b/app/ui/main_window_ui.py index b743748..5f27168 100644 --- a/app/ui/main_window_ui.py +++ b/app/ui/main_window_ui.py @@ -14,82 +14,149 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(800, 574) + MainWindow.resize(709, 1100) + MainWindow.setAutoFillBackground(False) + MainWindow.setStyleSheet("background-color: #232834;") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") - self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) - self.gridLayout.setObjectName("gridLayout") - self.label = QtWidgets.QLabel(self.centralwidget) - self.label.setObjectName("label") - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) - self.lblUsername = QtWidgets.QLabel(self.centralwidget) - self.lblUsername.setText("") - self.lblUsername.setObjectName("lblUsername") - self.gridLayout.addWidget(self.lblUsername, 0, 1, 1, 1) + self.txtPost = QtWidgets.QTextEdit(self.centralwidget) + self.txtPost.setGeometry(QtCore.QRect(10, 90, 351, 681)) + self.txtPost.setMinimumSize(QtCore.QSize(341, 181)) + self.txtPost.setStyleSheet("background-color: rgb(154, 153, 150); border-radius: 10px; \n" +"") + self.txtPost.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.txtPost.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) + self.txtPost.setObjectName("txtPost") self.lblPicture = QtWidgets.QLabel(self.centralwidget) + self.lblPicture.setGeometry(QtCore.QRect(20, 770, 351, 191)) + self.lblPicture.setMinimumSize(QtCore.QSize(0, 181)) + self.lblPicture.setFrameShape(QtWidgets.QFrame.StyledPanel) self.lblPicture.setText("") self.lblPicture.setObjectName("lblPicture") - self.gridLayout.addWidget(self.lblPicture, 0, 2, 3, 3) - self.btnNext = QtWidgets.QPushButton(self.centralwidget) - self.btnNext.setText("") + self.txtHashtags = QtWidgets.QTextEdit(self.centralwidget) + self.txtHashtags.setGeometry(QtCore.QRect(370, 90, 331, 871)) + self.txtHashtags.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.txtHashtags.setFrameShadow(QtWidgets.QFrame.Sunken) + self.txtHashtags.setObjectName("txtHashtags") + self.txtBoosted = QtWidgets.QTextEdit(self.centralwidget) + self.txtBoosted.setGeometry(QtCore.QRect(10, 0, 361, 31)) + self.txtBoosted.setMinimumSize(QtCore.QSize(0, 29)) + self.txtBoosted.setMaximumSize(QtCore.QSize(16777215, 29)) + font = QtGui.QFont() + font.setPointSize(13) + self.txtBoosted.setFont(font) + self.txtBoosted.setFrameShape(QtWidgets.QFrame.NoFrame) + self.txtBoosted.setFrameShadow(QtWidgets.QFrame.Plain) + self.txtBoosted.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.txtBoosted.setObjectName("txtBoosted") + self.layoutWidget = QtWidgets.QWidget(self.centralwidget) + self.layoutWidget.setGeometry(QtCore.QRect(10, 980, 701, 63)) + self.layoutWidget.setObjectName("layoutWidget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.btnFirst = QtWidgets.QPushButton(self.layoutWidget) + self.btnFirst.setMinimumSize(QtCore.QSize(61, 61)) + self.btnFirst.setMaximumSize(QtCore.QSize(61, 61)) + self.btnFirst.setText("") icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/buttons/icons8-next-page-48.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.btnNext.setIcon(icon) - self.btnNext.setIconSize(QtCore.QSize(48, 48)) - self.btnNext.setObjectName("btnNext") - self.gridLayout.addWidget(self.btnNext, 0, 5, 2, 1) - self.label_2 = QtWidgets.QLabel(self.centralwidget) - self.label_2.setObjectName("label_2") - self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) - self.textEdit_2 = QtWidgets.QTextEdit(self.centralwidget) - self.textEdit_2.setMarkdown("") - self.textEdit_2.setObjectName("textEdit_2") - self.gridLayout.addWidget(self.textEdit_2, 2, 0, 2, 2) - self.btnPrev = QtWidgets.QPushButton(self.centralwidget) + icon.addPixmap(QtGui.QPixmap(":/buttons/double-left.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnFirst.setIcon(icon) + self.btnFirst.setIconSize(QtCore.QSize(48, 48)) + self.btnFirst.setObjectName("btnFirst") + self.horizontalLayout.addWidget(self.btnFirst) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.btnPrev = QtWidgets.QPushButton(self.layoutWidget) + self.btnPrev.setMinimumSize(QtCore.QSize(61, 61)) + self.btnPrev.setMaximumSize(QtCore.QSize(61, 61)) self.btnPrev.setText("") icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(":/buttons/icons8-prev-page-48.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.btnPrev.setIcon(icon1) self.btnPrev.setIconSize(QtCore.QSize(48, 48)) self.btnPrev.setObjectName("btnPrev") - self.gridLayout.addWidget(self.btnPrev, 2, 5, 1, 1) - self.textEdit = QtWidgets.QTextEdit(self.centralwidget) - self.textEdit.setMarkdown("") - self.textEdit.setObjectName("textEdit") - self.gridLayout.addWidget(self.textEdit, 3, 2, 1, 4) - self.label_3 = QtWidgets.QLabel(self.centralwidget) - font = QtGui.QFont() - font.setPointSize(72) - font.setBold(True) - font.setWeight(75) - self.label_3.setFont(font) - self.label_3.setLineWidth(2) - self.label_3.setObjectName("label_3") - self.gridLayout.addWidget(self.label_3, 4, 0, 1, 2) - self.btnDislike = QtWidgets.QPushButton(self.centralwidget) + self.horizontalLayout.addWidget(self.btnPrev) + self.btnDislike = QtWidgets.QPushButton(self.layoutWidget) + self.btnDislike.setMinimumSize(QtCore.QSize(106, 61)) + self.btnDislike.setMaximumSize(QtCore.QSize(106, 61)) + self.btnDislike.setText("") icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(":/buttons/red-cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.btnDislike.setIcon(icon2) self.btnDislike.setIconSize(QtCore.QSize(48, 48)) self.btnDislike.setObjectName("btnDislike") - self.gridLayout.addWidget(self.btnDislike, 4, 2, 1, 1) - self.btnUnsure = QtWidgets.QPushButton(self.centralwidget) + self.horizontalLayout.addWidget(self.btnDislike) + self.btnUnsure = QtWidgets.QPushButton(self.layoutWidget) + self.btnUnsure.setMinimumSize(QtCore.QSize(106, 61)) + self.btnUnsure.setMaximumSize(QtCore.QSize(106, 61)) + self.btnUnsure.setText("") icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap(":/buttons/dont-know-woman.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.btnUnsure.setIcon(icon3) self.btnUnsure.setIconSize(QtCore.QSize(48, 48)) self.btnUnsure.setObjectName("btnUnsure") - self.gridLayout.addWidget(self.btnUnsure, 4, 3, 1, 1) - self.btnLike = QtWidgets.QPushButton(self.centralwidget) + self.horizontalLayout.addWidget(self.btnUnsure) + self.line_2 = QtWidgets.QFrame(self.layoutWidget) + self.line_2.setStyleSheet("background-color: rgb(94, 92, 100);") + self.line_2.setFrameShape(QtWidgets.QFrame.VLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.horizontalLayout.addWidget(self.line_2) + self.btnLike = QtWidgets.QPushButton(self.layoutWidget) + self.btnLike.setMinimumSize(QtCore.QSize(106, 61)) + self.btnLike.setMaximumSize(QtCore.QSize(106, 61)) + self.btnLike.setText("") icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap(":/buttons/green-tick.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.btnLike.setIcon(icon4) self.btnLike.setIconSize(QtCore.QSize(48, 48)) self.btnLike.setObjectName("btnLike") - self.gridLayout.addWidget(self.btnLike, 4, 4, 1, 2) + self.horizontalLayout.addWidget(self.btnLike) + self.btnNext = QtWidgets.QPushButton(self.layoutWidget) + self.btnNext.setMinimumSize(QtCore.QSize(61, 61)) + self.btnNext.setMaximumSize(QtCore.QSize(61, 61)) + self.btnNext.setText("") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(":/buttons/icons8-next-page-48.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnNext.setIcon(icon5) + self.btnNext.setIconSize(QtCore.QSize(48, 48)) + self.btnNext.setObjectName("btnNext") + self.horizontalLayout.addWidget(self.btnNext) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.btnLast = QtWidgets.QPushButton(self.layoutWidget) + self.btnLast.setMinimumSize(QtCore.QSize(61, 61)) + self.btnLast.setMaximumSize(QtCore.QSize(61, 61)) + self.btnLast.setText("") + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap(":/buttons/double-right.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnLast.setIcon(icon6) + self.btnLast.setIconSize(QtCore.QSize(48, 48)) + self.btnLast.setObjectName("btnLast") + self.horizontalLayout.addWidget(self.btnLast) + self.lblAcct = QtWidgets.QLabel(self.centralwidget) + self.lblAcct.setGeometry(QtCore.QRect(10, 60, 361, 29)) + self.lblAcct.setMinimumSize(QtCore.QSize(0, 29)) + self.lblAcct.setMaximumSize(QtCore.QSize(16777215, 29)) + self.lblAcct.setStyleSheet("color: rgb(119, 118, 123);") + self.lblAcct.setObjectName("lblAcct") + self.txtUsername = QtWidgets.QTextEdit(self.centralwidget) + self.txtUsername.setGeometry(QtCore.QRect(10, 30, 361, 29)) + self.txtUsername.setMinimumSize(QtCore.QSize(0, 29)) + self.txtUsername.setMaximumSize(QtCore.QSize(16777215, 29)) + self.txtUsername.setFrameShape(QtWidgets.QFrame.NoFrame) + self.txtUsername.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.txtUsername.setObjectName("txtUsername") + self.line = QtWidgets.QFrame(self.centralwidget) + self.line.setGeometry(QtCore.QRect(366, 90, 2, 871)) + self.line.setStyleSheet("background-color: rgb(119, 118, 123);") + self.line.setFrameShape(QtWidgets.QFrame.VLine) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setObjectName("line") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 709, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) @@ -101,21 +168,26 @@ class Ui_MainWindow(object): def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "Urma")) - self.label.setText(_translate("MainWindow", "Username:")) - self.label_2.setText(_translate("MainWindow", "Hashtags:")) - self.textEdit_2.setHtml(_translate("MainWindow", "\n" + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.txtPost.setHtml(_translate("MainWindow", "\n" "\n" -"


")) - self.textEdit.setHtml(_translate("MainWindow", "\n" +"

The magic of adulthood is in finding new and interesting ways of being disappointed <a href="xxx">thisn</a> https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md
and some black text

")) + self.txtHashtags.setHtml(_translate("MainWindow", "\n" "\n" -"


")) - self.label_3.setText(_translate("MainWindow", "urma")) - self.btnDislike.setText(_translate("MainWindow", "Dislike")) - self.btnUnsure.setText(_translate("MainWindow", "Not sure")) - self.btnLike.setText(_translate("MainWindow", "Like")) +"

#notthis
#orthis

#butthis
#notthis
#yes
#yes
#no

")) + self.txtBoosted.setHtml(_translate("MainWindow", "\n" +"\n" +"

Boosted by Jon Baker

")) + self.lblAcct.setText(_translate("MainWindow", "@JonBaker@mastodon.xyz")) + self.txtUsername.setHtml(_translate("MainWindow", "\n" +"\n" +"

Jon Baker

")) import urma_rc diff --git a/app/ui/urma.qrc b/app/ui/urma.qrc index 7f0c42d..97a71e1 100644 --- a/app/ui/urma.qrc +++ b/app/ui/urma.qrc @@ -1,5 +1,7 @@ + double-left.png + double-right.png icons8-next-page-48.png icons8-prev-page-48.png dont-know-woman.png diff --git a/app/urma.py b/app/urma.py index 9f89fc7..10cb7e8 100755 --- a/app/urma.py +++ b/app/urma.py @@ -1,6 +1,7 @@ #! /usr/bin/env python import ipdb +import os import pickle import random import stackprinter @@ -8,6 +9,10 @@ import sys from config import Config from dbconfig import engine, Session, scoped_session +from helpers import ( + index_ojects_by_parameter, + send_mail, +) from log import log from mastodon import Mastodon from models import ( @@ -19,6 +24,8 @@ from models import ( PostTags, ) +from typing import List + from PyQt5.QtWidgets import ( QApplication, QLabel, @@ -41,23 +48,70 @@ TESTDATA = "/home/kae/git/urma/hometl.pickle" # mastodon = Mastodon(client_id = 'urma_clientcred.secret',) # mastodon.log_in('kae@midnighthax.com', '^ZUaiC8P6vLV49', # to_file='urma_usercred.secret') -# hometl = Mastodon.timeline() -# hometl = mastodon.timeline() -# hometl -# len(hometl) -# hometl0=hometl[0] -# hometl0 -# history -# mastodon.me() -# following=mastodon.account_following(kaeid) -# len(following) -# following[0] -# following[39] -# following._pagination_next -# following._pagination_prev -# history -# mastodon = mastodon(access_token=Config.ACCESS_TOKEN) + +class MastodonAPI: + def __init__(self, access_token: str) -> None: + """ + Initialise access to Mastodon + """ + + self.mastodon = Mastodon(access_token=access_token) + self.me = self.mastodon.me() + + def get_account_following(self): + """ + Return a list of account_dicts that we are following + """ + + page1 = self.mastodon.account_following(self.me.id) + + return self.mastodon.fetch_remaining(page1) + + def get_hashtag_following(self): + """ + Return a list of hashtag_dicts that we are following + """ + + page1 = self.mastodon.tag_following(self.me.id) + + return self.mastodon.fetch_remaining(page1) + + +class UnratedPosts: + """ + Return unrated posts one at a time + """ + + def __init__(self, session: Session) -> None: + self.dataset = Posts.get_unrated_posts(session) + self.pointer = None + + def next(self) -> Posts: + # Set to first record if this is the first time we're called + if self.pointer is None: + self.pointer = 0 + else: + self.pointer += 1 + if self.pointer >= len(self.dataset): + # We've reached end of dataset + self.pointer = None + return None + else: + return self.dataset[self.pointer] + + def prev(self) -> Posts: + # Set to last record if this is the first time we're called + if self.pointer is None: + self.pointer = len(self.dataset) - 1 + else: + self.pointer -= 1 + if self.pointer < 0: + # We've reached end of dataset + self.pointer = None + return None + else: + return self.dataset[self.pointer] class Window(QMainWindow, Ui_MainWindow): @@ -65,6 +119,121 @@ class Window(QMainWindow, Ui_MainWindow): super().__init__(parent) self.setupUi(self) + self.mastapi = MastodonAPI(Config.ACCESS_TOKEN) + self.btnNext.clicked.connect(self.next) + self.btnPrev.clicked.connect(self.prev) + + with Session() as session: + self.dataset = UnratedPosts(session) + record = self.dataset.next() + self.display(session, record) + self.update_followed_accounts(session) + self.update_followed_hashtags(session) + import ipdb; ipdb.set_trace() + + def display(self, session: Session, record: UnratedPosts) -> None: + """ + Display passed post + """ + + if not record: + return + + if record not in session: + session.add(record) + self.txtUsername.setText(record.account.username) + if record.reblog: + self.txtBoosted.setEnabled(True) + self.display + elif record.child_id: + self.txtBoosted.setEnabled(True) + self.txtPost.setText("reblog child") + else: + self.txtPost.setHtml(record.content) + unfollowed_hashtags = [ + a.name for a in record.hashtags if not a.followed] + followed_hashtags = [a.name for a in record.hashtags if a.followed] + hasttag_text = ( + f"Followed: {', '.join(followed_hashtags)}\n\n" + f"Unfollowed: {', '.join(unfollowed_hashtags)}\n\n" + ) + self.txtHashtags.setText(hasttag_text) + + def next(self) -> None: + with Session() as session: + record = self.dataset.next() + self.display(session, record) + + def prev(self) -> None: + with Session() as session: + record = self.dataset.prev() + self.display(session, record) + + def update_followed_accounts(self, session: Session) -> None: + """ + Retrieve list of followed accounts and update accounts + in database to match + """ + + mast_followed_accounts = self.mastapi.get_account_following() + mast_followed_accounts_d = index_ojects_by_parameter( + mast_followed_accounts, "username") + + our_followed_accounts = Accounts.get_followed(session) + our_followed_accounts_d = index_ojects_by_parameter( + our_followed_accounts, "username") + + # Add those we are missing + for username in ( + set(mast_followed_accounts_d.keys()) - + set(our_followed_accounts_d.keys()) + ): + account = Accounts.get_or_create( + session, str(mast_followed_accounts_d[username].id) + ) + account.followed = True + + # Remove any we no longer follow + for username in ( + set(our_followed_accounts_d.keys()) - + set(mast_followed_accounts_d.keys()) + ): + account = Accounts.get_or_create( + session, str(our_followed_accounts_d[username].account_id) + ) + account.followed = False + + def update_followed_hashtags(self, session: Session) -> None: + """ + Retrieve list of followed hashtags and update hashtags + """ + + mast_followed_hashtags = self.mastapi.get_hashtag_following() + mast_followed_hashtags_d = index_ojects_by_parameter( + mast_followed_hashtags, "name") + + our_followed_hashtags = Hashtags.get_followed(session) + our_followed_hashtags_d = index_ojects_by_parameter( + our_followed_hashtags, "name") + + # Add those we are missing + for name in ( + set(mast_followed_hashtags_d.keys()) - + set(our_followed_hashtags_d.keys()) + ): + hashtag = Hashtags.get_or_create( + session, name, mast_followed_hashtags_d[name].url) + hashtag.followed = True + + # Remove any we no longer follow + for name in ( + set(our_followed_hashtags_d.keys()) - + set(mast_followed_hashtags_d.keys()) + ): + hashtag = hashtags.get_or_create( + session, name, our_followed_hashtags_d[username].name) + hashtag.followed = False + # class HoldingPot: # def process_post(post): @@ -131,11 +300,11 @@ if __name__ == "__main__": win.show() sys.exit(app.exec()) except Exception as exc: - from helpers import send_mail - msg = stackprinter.format(exc) - send_mail(Config.ERRORS_TO, Config.ERRORS_FROM, - "Exception from urma", msg) + if os.environ["URMA_ENV"] != "DEVELOPMENT": + msg = stackprinter.format(exc) + send_mail(Config.ERRORS_TO, Config.ERRORS_FROM, + "Exception from urma", msg) print("\033[1;31;47mUnhandled exception starts") stackprinter.show(style="darkbg")