Compare commits

..

2 Commits

Author SHA1 Message Date
Keith Edmunds
f034ef4f56 Restarted alembic 2023-01-06 20:45:16 +00:00
Keith Edmunds
a25c6819ff Updating accounts and hashtags in db from Mastodon works 2023-01-06 20:42:56 +00:00
22 changed files with 1156 additions and 531 deletions

View File

@ -4,11 +4,20 @@
# path to migration scripts
script_location = migrations
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
# for all available tokens
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
# timezone to use when rendering the date
# within the migration file as well as the filename.
# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library that can be
# installed by adding `alembic[tz]` to the pip requirements
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =
@ -26,10 +35,21 @@ script_location = migrations
# versions/ directory
# sourceless = false
# version location specification; this defaults
# version location specification; This defaults
# to migrations/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat migrations/versions
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator" below.
# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions
# version path separator; As mentioned above, this is the character used to split
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
# Valid values for version_path_separator are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
# the output encoding used when revision files
# are written from script.py.mako
@ -44,10 +64,10 @@ sqlalchemy.url = driver://user:pass@localhost/dbname
# detail and examples
# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks=black
# black.type=console_scripts
# black.entrypoint=black
# black.options=-l 79
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME
# Logging configuration
[loggers]

View File

@ -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

View File

@ -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

View File

@ -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'

BIN
app/ui/double-left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
app/ui/double-right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -6,181 +6,468 @@
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>574</height>
<width>709</width>
<height>1100</height>
</rect>
</property>
<property name="windowTitle">
<string>Urma</string>
<string>MainWindow</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: #232834;</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Username:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblUsername">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="3" colspan="3">
<widget class="QLabel" name="lblPicture">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="5" rowspan="2">
<widget class="QPushButton" name="btnNext">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-next-page-48.png</normaloff>:/buttons/icons8-next-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Hashtags:</string>
</property>
</widget>
</item>
<item row="2" column="0" rowspan="2" colspan="2">
<widget class="QTextEdit" name="textEdit_2">
<property name="markdown">
<string/>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
<widget class="QTextEdit" name="txtPost">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>351</width>
<height>681</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>341</width>
<height>181</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(154, 153, 150); border-radius: 10px;
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:8px; margin-bottom:8px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QPushButton" name="btnPrev">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-prev-page-48.png</normaloff>:/buttons/icons8-prev-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="3" column="2" colspan="4">
<widget class="QTextEdit" name="textEdit">
<property name="markdown">
<string/>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; color:#ffffff;&quot;&gt;The magic of adulthood is in finding new and interesting ways of being disappointed &lt;/span&gt;&lt;span style=&quot; color:#5e5c64;&quot;&gt;&amp;lt;a href=&amp;quot;xxx&amp;quot;&amp;gt;thisn&amp;lt;/a&amp;gt; &lt;/span&gt;&lt;a href=&quot;https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md &lt;br /&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://discu.eu/q/https://github.com/marsupialtail/quokka/blob/master/blog/why.md&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#000000;&quot;&gt;and some black text&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QLabel" name="lblPicture">
<property name="geometry">
<rect>
<x>20</x>
<y>770</y>
<width>351</width>
<height>191</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>181</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QTextEdit" name="txtHashtags">
<property name="geometry">
<rect>
<x>370</x>
<y>90</y>
<width>331</width>
<height>871</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<pointsize>72</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="lineWidth">
<number>2</number>
</property>
<property name="text">
<string>urma</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="btnDislike">
<property name="text">
<string>Dislike</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/red-cross.png</normaloff>:/buttons/red-cross.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="btnUnsure">
<property name="text">
<string>Not sure</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/dont-know-woman.png</normaloff>:/buttons/dont-know-woman.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="4" column="4" colspan="2">
<widget class="QPushButton" name="btnLike">
<property name="text">
<string>Like</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/green-tick.png</normaloff>:/buttons/green-tick.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
</layout>
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; color:#f6f5f4;&quot;&gt;#notthis&lt;br /&gt;#orthis&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot; color:#8ae234;&quot;&gt;#butthis&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot; color:#f6f5f4;&quot;&gt;#notthis&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot; color:#8ae234;&quot;&gt;#yes&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot; color:#8ae234;&quot;&gt;#yes&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot; color:#ffffff;&quot;&gt;#no&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QTextEdit" name="txtBoosted">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>361</width>
<height>31</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>29</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>29</height>
</size>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; color:#5e5c64;&quot;&gt;Boosted by&lt;/span&gt;&lt;span style=&quot; color:#f6f5f4;&quot;&gt; Jon&lt;/span&gt; &lt;span style=&quot; color:#8ae234;&quot;&gt;Baker&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>980</y>
<width>701</width>
<height>63</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnFirst">
<property name="minimumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/double-left.png</normaloff>:/buttons/double-left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnPrev">
<property name="minimumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-prev-page-48.png</normaloff>:/buttons/icons8-prev-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDislike">
<property name="minimumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/red-cross.png</normaloff>:/buttons/red-cross.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUnsure">
<property name="minimumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/dont-know-woman.png</normaloff>:/buttons/dont-know-woman.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLike">
<property name="minimumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>106</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/green-tick.png</normaloff>:/buttons/green-tick.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNext">
<property name="minimumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-next-page-48.png</normaloff>:/buttons/icons8-next-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnLast">
<property name="minimumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>61</width>
<height>61</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/double-right.png</normaloff>:/buttons/double-right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QLabel" name="lblAcct">
<property name="geometry">
<rect>
<x>10</x>
<y>60</y>
<width>361</width>
<height>29</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>29</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>29</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(119, 118, 123);</string>
</property>
<property name="text">
<string>@JonBaker@mastodon.xyz</string>
</property>
</widget>
<widget class="QTextEdit" name="txtUsername">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>361</width>
<height>29</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>29</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>29</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; color:#f6f5f4;&quot;&gt;Jon&lt;/span&gt; &lt;span style=&quot; color:#8ae234;&quot;&gt;Baker&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="Line" name="line">
<property name="geometry">
<rect>
<x>366</x>
<y>90</y>
<width>2</width>
<height>871</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(119, 118, 123);</string>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<width>709</width>
<height>26</height>
</rect>
</property>

View File

@ -0,0 +1,281 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>533</height>
</rect>
</property>
<property name="windowTitle">
<string>Urma</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>93</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Username:</string>
</property>
</widget>
<widget class="QLabel" name="lblUsername">
<property name="geometry">
<rect>
<x>140</x>
<y>9</y>
<width>16</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btnNext">
<property name="geometry">
<rect>
<x>731</x>
<y>9</y>
<width>60</width>
<height>54</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-next-page-48.png</normaloff>:/buttons/icons8-next-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>20</x>
<y>90</y>
<width>86</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Hashtags:</string>
</property>
</widget>
<widget class="QTextEdit" name="txtHashtags">
<property name="geometry">
<rect>
<x>20</x>
<y>121</y>
<width>256</width>
<height>251</height>
</rect>
</property>
<property name="markdown">
<string/>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:8px; margin-bottom:8px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="btnPrev">
<property name="geometry">
<rect>
<x>731</x>
<y>183</y>
<width>60</width>
<height>54</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/icons8-prev-page-48.png</normaloff>:/buttons/icons8-prev-page-48.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
<widget class="QLabel" name="lblBoosted">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>10</x>
<y>40</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color rgb(200, 0, 3);</string>
</property>
<property name="text">
<string>Boosted</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>10</x>
<y>358</y>
<width>281</width>
<height>113</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>72</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="lineWidth">
<number>2</number>
</property>
<property name="text">
<string>urma</string>
</property>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>290</x>
<y>10</y>
<width>358</width>
<height>441</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblPicture">
<property name="minimumSize">
<size>
<width>0</width>
<height>160</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QTextEdit" name="txtPost">
<property name="markdown">
<string/>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btnDislike">
<property name="text">
<string>Dislike</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/red-cross.png</normaloff>:/buttons/red-cross.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="btnUnsure">
<property name="text">
<string>Not sure</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/dont-know-woman.png</normaloff>:/buttons/dont-know-woman.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnLike">
<property name="text">
<string>Like</string>
</property>
<property name="icon">
<iconset resource="urma.qrc">
<normaloff>:/buttons/green-tick.png</normaloff>:/buttons/green-tick.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources>
<include location="urma.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -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", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.txtPost.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<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>"))
self.textEdit.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<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>"))
self.txtHashtags.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<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>"))
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"))
"<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>"))
self.txtBoosted.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<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>"))
self.lblAcct.setText(_translate("MainWindow", "@JonBaker@mastodon.xyz"))
self.txtUsername.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<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>"))
import urma_rc

View File

@ -1,5 +1,7 @@
<RCC>
<qresource prefix="buttons">
<file>double-left.png</file>
<file>double-right.png</file>
<file>icons8-next-page-48.png</file>
<file>icons8-prev-page-48.png</file>
<file>dont-know-woman.png</file>

View File

@ -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")

View File

@ -16,9 +16,9 @@ branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
def upgrade() -> None:
${upgrades if upgrades else "pass"}
def downgrade():
def downgrade() -> None:
${downgrades if downgrades else "pass"}

View File

@ -1,34 +0,0 @@
"""Fixing table relationships
Revision ID: 0d4c8f368e00
Revises: 5281c8c8059d
Create Date: 2023-01-02 14:28:57.905087
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '0d4c8f368e00'
down_revision = '5281c8c8059d'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('post_tags', sa.Column('post_id', sa.Integer(), nullable=False))
op.drop_constraint('post_tags_ibfk_2', 'post_tags', type_='foreignkey')
op.create_foreign_key(None, 'post_tags', 'posts', ['post_id'], ['id'])
op.drop_column('post_tags', 'posts_id')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('post_tags', sa.Column('posts_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.drop_constraint(None, 'post_tags', type_='foreignkey')
op.create_foreign_key('post_tags_ibfk_2', 'post_tags', 'posts', ['posts_id'], ['id'])
op.drop_column('post_tags', 'post_id')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 1132a20d56cb
Revises: 4a6731c9e71b
Create Date: 2023-01-02 13:13:07.084963
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1132a20d56cb'
down_revision = '4a6731c9e71b'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 28448b5f994f
Revises: 1132a20d56cb
Create Date: 2023-01-02 13:15:19.817927
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '28448b5f994f'
down_revision = '1132a20d56cb'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('attachments', 'followed')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('attachments', sa.Column('followed', mysql.TINYINT(display_width=1), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 354c25d6adac
Revises: 0d4c8f368e00
Create Date: 2023-01-02 14:37:16.192979
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '354c25d6adac'
down_revision = '0d4c8f368e00'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -1,34 +0,0 @@
"""Fixing table relationships
Revision ID: 4a6731c9e71b
Revises: 563253042f7e
Create Date: 2023-01-02 13:12:21.344294
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '4a6731c9e71b'
down_revision = '563253042f7e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('posts', sa.Column('parent_id', sa.Integer(), nullable=True))
op.drop_constraint('posts_ibfk_2', 'posts', type_='foreignkey')
op.create_foreign_key(None, 'posts', 'posts', ['parent_id'], ['id'])
op.drop_column('posts', 'reblog_id')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('posts', sa.Column('reblog_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.drop_constraint(None, 'posts', type_='foreignkey')
op.create_foreign_key('posts_ibfk_2', 'posts', 'posts', ['reblog_id'], ['id'])
op.drop_column('posts', 'parent_id')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 5281c8c8059d
Revises: 28448b5f994f
Create Date: 2023-01-02 13:16:37.480999
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5281c8c8059d'
down_revision = '28448b5f994f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 563253042f7e
Revises: 7c67a545533e
Create Date: 2023-01-02 13:00:44.136697
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '563253042f7e'
down_revision = '7c67a545533e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Fixing table relationships
Revision ID: 7672338beb90
Revises: 354c25d6adac
Create Date: 2023-01-02 14:39:26.283627
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '7672338beb90'
down_revision = '354c25d6adac'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""Fixing table relationships
Revision ID: 7c67a545533e
Revises: 40a36c2e0e8d
Create Date: 2023-01-02 12:56:05.031475
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '7c67a545533e'
down_revision = '40a36c2e0e8d'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('accounts', sa.Column('followed', sa.Boolean(), nullable=False))
op.add_column('attachments', sa.Column('followed', sa.Boolean(), nullable=False))
op.add_column('hashtags', sa.Column('followed', sa.Boolean(), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('hashtags', 'followed')
op.drop_column('attachments', 'followed')
op.drop_column('accounts', 'followed')
# ### end Alembic commands ###

View File

@ -1,8 +1,8 @@
"""Initial Alembic configuration
"""Initial configuration
Revision ID: 40a36c2e0e8d
Revision ID: 9abe92907482
Revises:
Create Date: 2023-01-02 08:15:56.863042
Create Date: 2023-01-06 20:44:30.249858
"""
from alembic import op
@ -10,19 +10,19 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '40a36c2e0e8d'
revision = '9abe92907482'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###