A terminal based bulletin board for colorfield.space
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
10 KiB

#!/usr/bin/env python3
import os
import sys
import sqlite3 as sql
import datetime, time
import subprocess
import readline
import signal
class c:
black = ''
red = '\033[0;31m'
b_red = '\033[1;31m'
yellow = '\033[1;33m'
green = '\033[0;32m'
b_green = '\033[1;32m'
cyan = '\033[0;36m'
b_cyan = '\033[1;36m'
purple = '\033[1;35m'
blue = '\033[0;34m'
b_blue = '\033[1;34m'
white = '\033[1;37m'
end = '\033[0m'
db_path = '/usr/local/share/cspc/db/cspc'
userdir = os.path.expanduser('~')
user = os.path.split(userdir)[-1]
topic = None
post = None
available_ids = []
messages = []
last_log = False
def go_back():
global post
global topic
# If just viewed a post
if post and topic:
post = None
else:
post = None
topic = None
def get_prompt():
if post:
ident = 'Post'.format(post)
elif topic:
ident = 'Posts'.format(topic)
else:
ident = 'Topics'
return '{}CSPC [{}{}{}] {}>{} '.format(c.yellow, c.white, ident, c.yellow, c.b_green, c.end)
def get_data():
if post and topic:
get_single_post()
elif topic:
get_posts()
else:
get_topics()
def show_help():
help_menu = [
'{}add:{} add a new topic/post/reply (whichever is relavent tot he screen you are on)'.format(c.cyan, c.end),
'{}back:{} move up a level (post->posts->topics)'.format(c.cyan, c.end),
'{}help:{} display this menu'.format(c.cyan, c.end),
'{}item id:{} enter the item number to view it'.format(c.cyan, c.end),
'{}q, quit, exit:{} leave cspc'.format(c.cyan, c.end),
'{}posts created since your last login to cspc have dates in green{}'.format(c.green, c.end)
]
for x in help_menu:
messages.append(x)
def make_add():
action = False
if post and topic:
action = 'reply'
elif topic:
action = 'post'
else:
action = 'topic'
verify = input('{}Are you sure you would like to add a new {}{}{} (y/n)?{} '.format(c.cyan, c.b_blue, action, c.cyan, c.end))
verify = verify.lower()
if verify in ['y','yes','yeah','yup','ya']:
add_new(action)
def add_new(a):
header = " 5 10 15 20 25 30 35 40 45 50\n ....|....|....|....|....|....|....|....|....|....|"
title = None
body = None
if not a == 'reply':
title = input('{}Enter the new {}s title:{} '.format(c.white, a, c.end))
content = []
if not a == 'topic':
print('{}Enter your content. To finish, enter a period as the only\ntext on its row.{}'.format(c.yellow, c.end))
print(header)
while True:
line = input('{}>{} '.format(c.green, c.end))
if line == '.':
break
content.append(line)
confirm = input('{}Submit the new {} (y/n)?{} '.format(c.white, a, c.end))
if confirm.lower() in ['y','ya','yes','yeah']:
body = '\n'.join(content)
else:
print('{} not saved'.format(a))
return False
payload = {'title': title, 'body': body}
add_to_db(a, payload)
def parse_command(com):
global topic
global post
global messages
comlist = ['add', 'help', 'quit', 'back']
if com in ['back', 'b']:
go_back()
elif com in ['help', '?', 'h']:
show_help()
elif com in ['quit', 'q', 'exit']:
set_last_log()
sys.exit(0)
elif com == ['add', 'a', 'new']:
make_add()
else:
try:
ident = int(com)
if not ident in available_ids:
messages.append('{}ERROR: {} is not an available option!\n'.format(c.red, com, c.end))
return False
if not topic:
topic = ident
elif not post:
post = ident
else:
messages.append('{}A number command is not relevant right now...{}'.format(c.purple, c.end))
except ValueError:
messages.append('{}Input not recognized{}'.format(c.red, c.end))
#------- DB Related --------#
def check_and_build_db():
if not os.path.isfile(db_path):
conn = sql.connect(db_path)
c = conn.cursor()
c.execute("CREATE TABLE data (topic_id INTEGER DEFAULT NULL, post_id INTEGER DEFAULT NULL, type text NOT NULL, title text DEFAULT NULL, body text DEFAULT NULL, author text NOT NULL, last_updated INTEGER NOT NULL)")
conn.commit()
conn.close()
def db_do(query, var=False, noresval=False):
global messages
if os.path.isfile(db_path):
conn = sql.connect(db_path)
c = conn.cursor()
if var:
c.execute(query, var)
else:
c.execute(query)
if noresval:
out = c.rowcount
else:
out = []
for row in c:
out.append(row)
conn.commit()
conn.close()
return out
else:
messages.append("{}ERROR:{} Database cannot be found or is corrupt".format(c.red, c.end))
return False
def get_posts():
global available_ids
global topic
available_ids = []
q = "SELECT rowid, title, author, last_updated FROM data WHERE type = 'post' and topic_id = ? ORDER BY last_updated DESC"
v = (topic,)
res = db_do(q, v)
print('{}{:^6} {:35} {:12} {:18}{}'.format(c.yellow, 'ID', 'Post Title', 'Author', 'Last Updated', c.end))
print('{}------------------------------------------------------------------------------{}'.format( c.yellow, c.end))
if not len(res):
print('\n{}There are no posts for this topic yet. Add one!{}'.format(c.cyan, c.end))
else:
for row in res:
available_ids.append(row[0])
dtime = datetime.datetime.utcfromtimestamp(row[3]).strftime('%Y-%m-%d %H:%M')
title = row[1]
if len(title) > 35:
title = '{}...'.format(title[:32])
if last_log > row[3] or not last_log:
print('({:^4}) {:35} {:12} {:18}'.format(row[0], title, row[2], dtime))
else:
print('({:^4}) {:35} {:12} {}{:18}{}'.format(row[0], title, row[2], c.green, dtime, c.end))
return True
def get_topics():
global available_ids
available_ids = []
q = "SELECT title, last_updated, rowid FROM data WHERE type = 'topic' ORDER BY last_updated DESC"
res = db_do(q)
print('{}{:^6} {:35} {:18}{}'.format(c.yellow, 'ID', 'Topic Name', 'Last Updated', c.end))
print('{}-----------------------------------------------------------------{}'.format( c.yellow, c.end))
for row in res:
available_ids.append(row[2])
dtime = datetime.datetime.utcfromtimestamp(row[1]).strftime('%Y-%m-%d %H:%M')
title = row[0]
if len(title) > 35:
title = '{}...'.format(title[:32])
if last_log > row[1] or not last_log:
print('({:^4}) {}{:35}{} {:18}'.format(row[2], c.cyan, title, c.end, dtime))
else:
print('({:^4}) {}{:35} {}{:18}{}'.format(row[2], c.cyan, title, c.green, dtime, c.end))
return True
def get_single_post():
global topic
global post
q1 = "SELECT title, body, author, last_updated FROM data WHERE type = 'post' and topic_id = ? and rowid = ?"
v1 = (topic, post)
res1 = db_do(q1, v1)
q2 = "SELECT body, author, last_updated FROM data WHERE type = 'reply' and post_id = ? and topic_id = ? ORDER BY last_updated ASC"
v2 = (post, topic)
res2 = db_do(q2, v2)
post_title = "{}Title:{} {}{}".format(c.yellow, c.white, res1[0][0], c.end)
post_author = "{}Author:{} {}{}".format(c.yellow, c.white, res1[0][2], c.end)
dtime = datetime.datetime.utcfromtimestamp(res1[0][3]).strftime('%Y-%m-%d %H:%M')
post_time = "{}Post date:{} {}{}\n".format(c.yellow, c.white, dtime, c.end)
post_body = res1[0][1]
print(post_title)
print(post_author)
print(post_time)
print(post_body)
print("\n{}- - - - - - - - - - - - - - - -{}\n".format(c.white, c.end))
if len(res2):
for row in res2:
dtime = datetime.datetime.utcfromtimestamp(row[2]).strftime('%Y-%m-%d %H:%M')
print("{} | {}\n".format(row[1],dtime))
print(row[0])
print("\n- - - - - - -\n")
else:
print('No replies. Add one!')
def update_time(t):
if topic and post:
q = "UPDATE data SET last_updated = ? WHERE rowid in (?, ?)"
v = (t, topic, post)
elif topic:
q = "UPDATE data SET last_updated = ? WHERE rowid = ?"
v = (t, topic)
else:
return True
res = db_do(q, v, noresval=True)
return res
def add_to_db(action, data):
utime = int(time.time())
q = "INSERT INTO data VALUES (?, ?, ?, ?, ?, ?, ?)"
v = (topic, post, action, data['title'], data['body'], user, utime)
res = db_do(q, v, noresval=True)
if not res:
messages.append("{}ERROR:{} There was an error adding your topic".format(c.red, c.end))
return False
tupdate = update_time(utime)
return True
def get_last_log():
global last_log
filepath = '{}/.cspc'.format(userdir)
if not os.path.isfile(filepath):
with open(filepath, 'w') as f:
current = int(time.time())
f.write(str(current))
with open(filepath, 'r') as f:
data = f.read()
try:
last_log = int(data)
except:
last_log = False
def set_last_log():
filepath = '{}/.cspc'.format(userdir)
with open(filepath, 'w') as f:
current = int(time.time())
f.write(str(current))
#------- Main loop --------#
def mainloop():
global messages
while True:
subprocess.run(['clear'])
print('{}Colorfield Space Bulletin Board{}\n\n'.format(c.b_blue, c.end))
output = get_data()
# print the formatted data
print('')
for x in messages:
print(x)
print('')
command = input(get_prompt())
print('')
messages = []
if not command:
continue
parse_command(command)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal.SIG_IGN)
try:
check_and_build_db()
except sql.OperationalError:
print("No cspc instance installed. Is the database path valid?")
sys.exit(2)
get_last_log()
mainloop()