2016-05-15 03:44:03 +00:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import tempfile
|
|
|
|
import subprocess
|
|
|
|
import time
|
|
|
|
import json
|
|
|
|
from email.mime.text import MIMEText;
|
|
|
|
|
|
|
|
import core
|
|
|
|
import chatter
|
|
|
|
import inflect
|
|
|
|
import util
|
|
|
|
|
|
|
|
## system globals
|
|
|
|
SOURCE = os.path.join("/home", "endorphant", "projects", "ttbp", "bin")
|
|
|
|
LIVE = "http://tilde.town/~"
|
|
|
|
FEEDBACK = os.path.join("/home", "endorphant", "ttbp-mail")
|
|
|
|
FEEDBOX = "endorphant@tilde.town"
|
|
|
|
USERFILE = os.path.join("/home", "endorphant", "projects", "ttbp", "users.txt")
|
2016-05-20 15:06:42 +00:00
|
|
|
VERSION = "0.8.7"
|
2016-05-17 01:42:32 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
p = inflect.engine()
|
|
|
|
|
|
|
|
## user globals
|
|
|
|
USER = os.path.basename(os.path.expanduser("~"))
|
2016-05-17 01:42:32 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
PATH = os.path.join("/home", USER, ".ttbp")
|
|
|
|
PUBLIC = os.path.join("/home", USER, "public_html")
|
|
|
|
WWW = os.path.join(PATH, "www")
|
|
|
|
CONFIG = os.path.join(PATH, "config")
|
|
|
|
TTBPRC = os.path.join(CONFIG, "ttbprc")
|
|
|
|
DATA = os.path.join(PATH, "entries")
|
|
|
|
SETTINGS = {
|
|
|
|
"editor": "none",
|
|
|
|
"publish dir": False
|
|
|
|
}
|
|
|
|
|
|
|
|
## ui globals
|
2016-05-20 03:19:02 +00:00
|
|
|
BANNER = util.attach_rainbow()+open(os.path.join(SOURCE, "config", "banner.txt")).read()+"~potentially volatile beta version~"+util.attach_reset()
|
|
|
|
SPACER = "\n"
|
2016-05-15 03:44:03 +00:00
|
|
|
INVALID = "please pick a number from the list of options!\n\n"
|
|
|
|
DUST = "sorry about the dust, but this part is still under construction. check back later!\n\n"
|
|
|
|
QUITS = ['exit', 'quit', 'q', 'x']
|
|
|
|
BACKS = ['back', 'b', 'q']
|
|
|
|
EJECT = "eject button fired! going home now."
|
|
|
|
|
|
|
|
## ref
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
EDITORS = ["vim", "vi", "emacs", "pico", "nano", "ed"]
|
2016-05-15 03:44:03 +00:00
|
|
|
SUBJECTS = ["help request", "bug report", "feature suggestion", "general comment"]
|
|
|
|
|
|
|
|
##
|
|
|
|
|
|
|
|
def redraw(leftover=""):
|
|
|
|
os.system("clear")
|
|
|
|
print(BANNER)
|
|
|
|
print(SPACER)
|
|
|
|
if leftover:
|
|
|
|
print("> "+leftover+"\n")
|
|
|
|
|
|
|
|
def start():
|
2016-05-16 04:49:36 +00:00
|
|
|
redraw()
|
|
|
|
#print(chatter.say("greet")+", "+chatter.say("friend"))
|
|
|
|
#print("(remember, you can always press ctrl-c to come home)\n")
|
|
|
|
print("""
|
2016-05-15 04:19:05 +00:00
|
|
|
if you don't want to be here at any point, press <ctrl-d> and it'll all go away.
|
|
|
|
just keep in mind that you might lose anything you've started here.\
|
|
|
|
""")
|
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
try:
|
2016-05-16 04:49:36 +00:00
|
|
|
print(check_init())
|
2016-05-15 03:44:03 +00:00
|
|
|
except EOFError:
|
|
|
|
print(stop())
|
2016-05-16 04:49:36 +00:00
|
|
|
return
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
##
|
2016-05-16 04:49:36 +00:00
|
|
|
redraw()
|
|
|
|
|
|
|
|
while 1:
|
|
|
|
try:
|
|
|
|
print(main_menu())
|
|
|
|
except EOFError:
|
|
|
|
print(stop())
|
|
|
|
break
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
redraw(EJECT)
|
|
|
|
else:
|
|
|
|
break
|
2016-05-15 03:44:03 +00:00
|
|
|
|
|
|
|
def stop():
|
2016-05-16 04:49:36 +00:00
|
|
|
return "\n\n\t"+chatter.say("bye")+"\n\n"
|
2016-05-15 03:44:03 +00:00
|
|
|
|
|
|
|
def check_init():
|
2016-05-20 03:19:02 +00:00
|
|
|
global SETTINGS
|
|
|
|
print("\n\n")
|
|
|
|
if os.path.exists(os.path.join(os.path.expanduser("~"),".ttbp")):
|
|
|
|
print(chatter.say("greet")+", "+USER+".\n")
|
|
|
|
while not os.path.isfile(TTBPRC):
|
|
|
|
setup_handler()
|
|
|
|
try:
|
|
|
|
SETTINGS = json.load(open(TTBPRC))
|
|
|
|
except ValueError:
|
|
|
|
setup_handler()
|
|
|
|
|
|
|
|
## PATCH CHECK HERE
|
|
|
|
if not updated():
|
|
|
|
print(update_version())
|
|
|
|
|
|
|
|
raw_input("press <enter> to explore your feels.\n\n")
|
|
|
|
core.load()
|
|
|
|
|
|
|
|
return ""
|
|
|
|
else:
|
|
|
|
return init()
|
2016-05-15 03:44:03 +00:00
|
|
|
|
|
|
|
def init():
|
|
|
|
try:
|
2016-05-15 04:19:05 +00:00
|
|
|
raw_input("""
|
|
|
|
i don't recognize you, stranger. let's make friends.
|
|
|
|
|
|
|
|
press <enter> to begin, or <ctrl-c> to get out of here.
|
|
|
|
""")
|
2016-05-15 03:44:03 +00:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
print("\n\nthanks for checking in! i'll always be here.\n\n")
|
|
|
|
quit()
|
|
|
|
|
|
|
|
users = open(USERFILE, 'a')
|
|
|
|
users.write(USER+"\n")
|
|
|
|
users.close()
|
|
|
|
subprocess.call(["mkdir", PATH])
|
|
|
|
subprocess.call(["mkdir", CONFIG])
|
|
|
|
subprocess.call(["mkdir", DATA])
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
header = gen_header()
|
|
|
|
headerfile = open(os.path.join(CONFIG, "header.txt"), 'w')
|
|
|
|
for line in header:
|
|
|
|
headerfile.write(line)
|
|
|
|
headerfile.close()
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
subprocess.call(["cp", os.path.join(SOURCE, "config", "defaults", "footer.txt"), CONFIG])
|
2016-05-17 01:42:32 +00:00
|
|
|
subprocess.call(["cp", os.path.join(SOURCE, "config", "defaults", "style.css"), CONFIG])
|
2016-05-15 03:44:03 +00:00
|
|
|
|
|
|
|
setup()
|
|
|
|
core.load()
|
|
|
|
|
|
|
|
raw_input("\nyou're all good to go, "+chatter.say("friend")+"! hit <enter> to continue.\n\n")
|
|
|
|
return ""
|
|
|
|
|
|
|
|
def gen_header():
|
2016-05-15 04:19:05 +00:00
|
|
|
header ="""
|
|
|
|
<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2//EN\">
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>~"""+USER+""" on TTBP</title>
|
|
|
|
<link rel=\"stylesheet\" href=\"style.css\" />
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id=\"meta\">
|
|
|
|
<h1><a href=\"index.html#\">~"""+USER+"""</a>@<a href=\"/~endorphant/ttbp\">TTBP</a></h1>
|
|
|
|
</div>
|
2016-05-17 01:42:32 +00:00
|
|
|
|
2016-05-15 04:19:05 +00:00
|
|
|
<!---put your custom html here-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!---don't put anything after this line-->
|
|
|
|
<div id=\"tlogs\">\
|
|
|
|
"""
|
2016-05-15 03:44:03 +00:00
|
|
|
return header
|
|
|
|
|
|
|
|
def setup_handler():
|
|
|
|
print("\nyour ttbp configuration doesn't look right. let's make you a fresh copy.\n\n")
|
|
|
|
try:
|
|
|
|
setup()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print("\n\nsorry, trying again.\n\n")
|
|
|
|
setup()
|
|
|
|
|
|
|
|
def setup():
|
|
|
|
global SETTINGS
|
|
|
|
|
|
|
|
# editor selection
|
2016-05-15 22:15:53 +00:00
|
|
|
SETTINGS.update({"editor": select_editor()})
|
2016-05-15 03:44:03 +00:00
|
|
|
redraw("text editor set to: "+SETTINGS["editor"])
|
|
|
|
|
2016-05-16 04:49:36 +00:00
|
|
|
# publishing selection
|
2016-05-15 22:15:53 +00:00
|
|
|
SETTINGS.update({"publishing":select_publishing()})
|
2016-05-20 03:19:02 +00:00
|
|
|
update_publishing()
|
2016-05-15 22:15:53 +00:00
|
|
|
redraw("blog publishing: "+str(publishing()))
|
|
|
|
|
|
|
|
if publishing():
|
2016-05-20 03:19:02 +00:00
|
|
|
print("publish directory: ~"+USER+"/public_html/"+SETTINGS.get("publish dir"))
|
2016-05-15 03:44:03 +00:00
|
|
|
# save settings
|
|
|
|
ttbprc = open(TTBPRC, "w")
|
|
|
|
ttbprc.write(json.dumps(SETTINGS, sort_keys=True, indent=2, separators=(',',':')))
|
|
|
|
ttbprc.close()
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
raw_input("\nyou're all good to go, "+chatter.say("friend")+"! hit <enter> to continue.\n\n")
|
|
|
|
redraw()
|
2016-05-15 03:44:03 +00:00
|
|
|
return SETTINGS
|
|
|
|
|
|
|
|
## menus
|
|
|
|
|
|
|
|
def print_menu(menu):
|
|
|
|
i = 0
|
|
|
|
for x in menu:
|
|
|
|
line = []
|
2016-05-15 04:37:43 +00:00
|
|
|
line.append(util.attach_rainbow())
|
2016-05-15 03:44:03 +00:00
|
|
|
line.append("\t[ ")
|
|
|
|
if i < 10:
|
|
|
|
line.append(" ")
|
|
|
|
line.append(str(i)+" ] "+x)
|
2016-05-15 04:37:43 +00:00
|
|
|
line.append(util.attach_reset())
|
2016-05-15 03:44:03 +00:00
|
|
|
print("".join(line))
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
def main_menu():
|
|
|
|
menuOptions = [
|
|
|
|
"record your feels",
|
|
|
|
"review your feels",
|
|
|
|
"check out your neighbors",
|
|
|
|
"browse global feels",
|
|
|
|
"change your settings",
|
|
|
|
"send some feedback",
|
|
|
|
"see credits"]
|
|
|
|
print("you're at ttbp home. remember, you can always press <ctrl-c> to come back here.\n\n")
|
|
|
|
#print("you're at ttbp home.\n\n")
|
|
|
|
print_menu(menuOptions)
|
|
|
|
|
|
|
|
try:
|
|
|
|
choice = raw_input("\ntell me about your feels (or 'quit' to exit): ")
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
redraw(EJECT)
|
|
|
|
return main_menu()
|
|
|
|
|
|
|
|
if choice == '0':
|
|
|
|
redraw()
|
|
|
|
today = time.strftime("%Y%m%d")
|
|
|
|
write_entry(os.path.join(DATA, today+".txt"))
|
2016-05-15 06:36:42 +00:00
|
|
|
www_neighbors(find_ttbps())
|
2016-05-15 03:44:03 +00:00
|
|
|
elif choice == '1':
|
2016-05-20 03:19:02 +00:00
|
|
|
redraw("here are your recorded feels, listed by date:\n")
|
2016-05-15 03:44:03 +00:00
|
|
|
view_own()
|
|
|
|
elif choice == '2':
|
|
|
|
users = find_ttbps()
|
2016-05-20 03:19:02 +00:00
|
|
|
redraw("the following "+p.no("user", len(users))+" "+p.plural("is", len(users))+" recording feels on ttbp:\n")
|
2016-05-15 03:44:03 +00:00
|
|
|
view_neighbors(users)
|
|
|
|
elif choice == '3':
|
2016-05-20 03:19:02 +00:00
|
|
|
redraw("now viewing most recent entries\n")
|
2016-05-15 03:44:03 +00:00
|
|
|
view_feed()
|
|
|
|
elif choice == '4':
|
2016-05-20 03:19:02 +00:00
|
|
|
pretty_settings = "\n\n\ttext editor:\t" +SETTINGS.get("editor")
|
|
|
|
if publishing():
|
|
|
|
pretty_settings += "\n\tpublish dir:\t" +os.path.join(PUBLIC, SETTINGS.get("publish dir"))
|
2016-05-15 22:15:53 +00:00
|
|
|
pretty_settings += "\n\tpubishing:\t"+str(SETTINGS.get("publishing"))
|
2016-05-15 03:44:03 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
redraw("now changing your settings. press <ctrl-c> if you didn't mean to do this."+pretty_settings+"\n")
|
2016-05-15 03:44:03 +00:00
|
|
|
try:
|
|
|
|
setup()
|
|
|
|
except KeyboardInterrupt():
|
|
|
|
redraw(EJECT)
|
|
|
|
redraw()
|
|
|
|
elif choice == '5':
|
|
|
|
feedback_menu()
|
|
|
|
elif choice == '6':
|
|
|
|
redraw()
|
|
|
|
show_credits()
|
|
|
|
elif choice in QUITS:
|
|
|
|
return stop()
|
|
|
|
else:
|
|
|
|
redraw(INVALID)
|
|
|
|
|
|
|
|
return main_menu()
|
|
|
|
|
|
|
|
###
|
|
|
|
|
|
|
|
def feedback_menu():
|
|
|
|
print("you're about to send mail to ~endorphant about ttbp\n\n")
|
|
|
|
|
|
|
|
print_menu(SUBJECTS)
|
|
|
|
choice = raw_input("\npick a category for your feedback: ")
|
|
|
|
|
|
|
|
cat = ""
|
|
|
|
if choice in ['0', '1', '2', '3']:
|
|
|
|
cat = SUBJECTS[int(choice)]
|
2016-05-15 04:19:05 +00:00
|
|
|
entered = raw_input("""
|
|
|
|
composing a """+cat+""" to ~endorphant.
|
|
|
|
|
|
|
|
press <enter> to open an external text editor. mail will be sent once you save and quit.
|
2016-05-15 04:22:05 +00:00
|
|
|
|
|
|
|
""")
|
2016-05-15 03:44:03 +00:00
|
|
|
redraw(send_feedback(entered, cat))
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
redraw(INVALID)
|
|
|
|
|
|
|
|
return feedback_menu()
|
|
|
|
|
|
|
|
def view_neighbors(users):
|
|
|
|
|
|
|
|
userList = []
|
|
|
|
|
|
|
|
for user in users:
|
|
|
|
userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc")))
|
2016-05-20 15:06:42 +00:00
|
|
|
url="\t\t\t\t"
|
|
|
|
if userRC.get("publish dir"):
|
|
|
|
url = LIVE+user+"/"+userRC.get("publish dir")
|
2016-05-15 03:44:03 +00:00
|
|
|
count = 0
|
|
|
|
lastfile = ""
|
|
|
|
files = os.listdir(os.path.join("/home", user, ".ttbp", "entries"))
|
|
|
|
files.sort()
|
|
|
|
for filename in files:
|
|
|
|
if core.valid(filename):
|
|
|
|
count += 1
|
|
|
|
lastfile = os.path.join("/home", user, ".ttbp", "entries", filename)
|
|
|
|
|
|
|
|
ago = "never"
|
|
|
|
if lastfile:
|
|
|
|
last = os.path.getctime(lastfile)
|
|
|
|
since = time.time()-last
|
|
|
|
ago = util.pretty_time(int(since)) + " ago"
|
|
|
|
else:
|
|
|
|
last = 0
|
|
|
|
|
|
|
|
pad = ""
|
|
|
|
if len(user) < 8:
|
|
|
|
pad = "\t"
|
|
|
|
user = "~"+user
|
|
|
|
if len(user) < 8:
|
|
|
|
user += "\t"
|
|
|
|
|
|
|
|
userList.append(["\t"+user+"\t"+url+pad+"\t("+ago+")", last])
|
|
|
|
|
|
|
|
# sort user by most recent entry
|
|
|
|
userList.sort(key = lambda userdata:userdata[1])
|
|
|
|
userList.reverse()
|
|
|
|
sortedUsers = []
|
|
|
|
for user in userList:
|
|
|
|
sortedUsers.append(user[0])
|
|
|
|
|
|
|
|
print_menu(sortedUsers)
|
|
|
|
|
|
|
|
raw_input("\n\npress <enter> to go back home.\n\n")
|
|
|
|
redraw()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
def view_own():
|
|
|
|
|
|
|
|
filenames = []
|
|
|
|
|
|
|
|
for entry in os.listdir(DATA):
|
|
|
|
filenames.append(os.path.join(DATA, entry))
|
|
|
|
metas = core.meta(filenames)
|
|
|
|
|
|
|
|
entries = []
|
|
|
|
for entry in metas:
|
|
|
|
entries.append(""+entry[4]+" ("+p.no("word", entry[2])+") ")
|
|
|
|
|
|
|
|
return view_entries(metas, entries, "here are your recorded feels, listed by date: \n\n")
|
|
|
|
|
|
|
|
def show_credits():
|
|
|
|
|
|
|
|
print("""
|
|
|
|
ttbp was written by ~endorphant in python. the codebase is
|
|
|
|
publicly available on github at https://github.com/modgethanc/ttbp
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
for the full changelog, see ~endorphant/projects/ttbp/changelog.txt
|
|
|
|
|
2016-05-15 04:22:05 +00:00
|
|
|
if you have ideas for ttbp, you are welcome to fork the repo and
|
|
|
|
work on it. i'm only a neophyte dev, so i apologize for any
|
2016-05-15 03:44:03 +00:00
|
|
|
horrendously ugly coding habits i have. i'd love to hear about your
|
|
|
|
ideas and brainstorm about new features!
|
|
|
|
|
|
|
|
thanks to everyone who reads, listens, writes, and feels.\
|
|
|
|
""")
|
|
|
|
|
|
|
|
raw_input("\n\npress <enter> to go back home.\n\n")
|
|
|
|
redraw()
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
## handlers
|
|
|
|
|
|
|
|
def write_entry(entry=os.path.join(DATA, "test.txt")):
|
|
|
|
|
2016-05-15 04:19:05 +00:00
|
|
|
entered = raw_input("""
|
2016-05-15 05:55:18 +00:00
|
|
|
"""+util.hilight("new feature!")+""" you can now use standard markdown in your entry text!
|
|
|
|
raw html is still valid, and you can mix them together.
|
2016-05-15 05:19:44 +00:00
|
|
|
|
2016-05-15 04:19:05 +00:00
|
|
|
feels will be recorded for today, """+time.strftime("%d %B %Y")+""".
|
|
|
|
|
|
|
|
if you've already started recording feels for this day, you
|
|
|
|
can pick up where you left off.
|
|
|
|
|
|
|
|
press <enter> to begin recording your feels.
|
2016-05-15 04:22:05 +00:00
|
|
|
|
|
|
|
""")
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
if entered:
|
|
|
|
entryFile = open(entry, "a")
|
|
|
|
entryFile.write("\n"+entered+"\n")
|
|
|
|
entryFile.close()
|
|
|
|
subprocess.call([SETTINGS["editor"], entry])
|
2016-05-16 05:02:06 +00:00
|
|
|
|
|
|
|
left = ""
|
|
|
|
|
|
|
|
if publishing():
|
|
|
|
core.load_files()
|
|
|
|
core.write("index.html")
|
2016-05-20 15:06:42 +00:00
|
|
|
left = "posted to "+LIVE+USER+"/"+SETTINGS["publish dir"]+"/index.html\n\n>"
|
2016-05-16 05:02:06 +00:00
|
|
|
redraw(left + " thanks for sharing your feels!")
|
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def send_feedback(entered, subject="none", mailbox=os.path.join(FEEDBACK, USER+"-"+time.strftime("%Y%m%d-%H%M")+".msg")):
|
|
|
|
|
|
|
|
message = ""
|
|
|
|
|
|
|
|
temp = tempfile.NamedTemporaryFile()
|
|
|
|
if entered:
|
|
|
|
msgFile = open(temp.name, "a")
|
|
|
|
msgFile.write(entered+"\n")
|
|
|
|
msgFile.close()
|
|
|
|
subprocess.call([SETTINGS["editor"], temp.name])
|
|
|
|
message = open(temp.name, 'r').read()
|
|
|
|
|
|
|
|
id = "#"+util.genID(3)
|
|
|
|
mail = MIMEText(message)
|
|
|
|
mail['To'] = FEEDBOX
|
|
|
|
mail['From'] = USER+"@tilde.town"
|
|
|
|
mail['Subject'] = " ".join(["[ttbp]", subject, id])
|
|
|
|
m = os.popen("/usr/sbin/sendmail -t -oi", 'w')
|
|
|
|
m.write(mail.as_string())
|
|
|
|
m.close()
|
|
|
|
|
|
|
|
return """\
|
|
|
|
thanks for writing! for your reference, it's been recorded
|
2016-05-15 04:22:05 +00:00
|
|
|
> as """+ " ".join([subject, id])+""". i'll try to respond to you soon.\
|
2016-05-15 03:44:03 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
def view_entries(metas, entries, prompt):
|
|
|
|
|
|
|
|
print_menu(entries)
|
|
|
|
|
|
|
|
choice = list_select(entries, "pick an entry from the list, or type 'back' to go home: ")
|
|
|
|
|
|
|
|
if choice is not False:
|
|
|
|
|
|
|
|
redraw("now reading ~"+metas[choice][5]+"'s feels on "+metas[choice][4]+"\n> press <q> to return to feels list.\n\n")
|
|
|
|
|
|
|
|
show_entry(metas[choice][0])
|
|
|
|
redraw(prompt)
|
|
|
|
|
|
|
|
return view_entries(metas, entries, prompt)
|
|
|
|
|
|
|
|
else:
|
|
|
|
redraw()
|
|
|
|
return
|
|
|
|
|
|
|
|
def show_entry(filename):
|
|
|
|
|
|
|
|
subprocess.call(["less", filename])
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
def view_feed():
|
|
|
|
|
|
|
|
feedList = []
|
|
|
|
|
|
|
|
for townie in find_ttbps():
|
|
|
|
entryDir = os.path.join("/home", townie, ".ttbp", "entries")
|
|
|
|
filenames = os.listdir(entryDir)
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
for entry in filenames:
|
|
|
|
if core.valid(entry):
|
|
|
|
feedList.append(os.path.join(entryDir, entry))
|
|
|
|
|
|
|
|
metas = core.meta(feedList)
|
|
|
|
metas.sort(key = lambda entry:entry[3])
|
|
|
|
metas.reverse()
|
|
|
|
|
|
|
|
entries = []
|
|
|
|
for entry in metas[0:10]:
|
|
|
|
pad = ""
|
|
|
|
if len(entry[5]) < 8:
|
|
|
|
pad = "\t"
|
|
|
|
|
|
|
|
entries.append("~"+entry[5]+pad+"\ton "+entry[3]+" ("+p.no("word", entry[2])+") ")
|
|
|
|
|
|
|
|
#print_menu(entries)
|
|
|
|
view_entries(metas, entries, "most recent ten entries: \n\n")
|
|
|
|
|
|
|
|
redraw()
|
|
|
|
|
|
|
|
return
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
#####
|
|
|
|
|
|
|
|
def find_ttbps():
|
|
|
|
# looks for users with a valid ttbp config and returns a list of them
|
|
|
|
users = []
|
|
|
|
|
|
|
|
for townie in os.listdir("/home"):
|
|
|
|
if os.path.exists(os.path.join("/home", townie, ".ttbp", "config", "ttbprc")):
|
|
|
|
users.append(townie)
|
|
|
|
|
|
|
|
return users
|
|
|
|
|
2016-05-15 06:36:42 +00:00
|
|
|
def www_neighbors(users):
|
|
|
|
# takes a raw list of valid users and formats for www view
|
|
|
|
|
|
|
|
userList = []
|
|
|
|
|
|
|
|
for user in users:
|
2016-05-15 22:15:53 +00:00
|
|
|
if not publishing(user):
|
|
|
|
continue
|
|
|
|
|
2016-05-15 06:36:42 +00:00
|
|
|
userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc")))
|
2016-05-15 22:15:53 +00:00
|
|
|
|
2016-05-15 06:36:42 +00:00
|
|
|
url = LIVE+user+"/"+userRC["publish dir"]
|
2016-05-15 22:15:53 +00:00
|
|
|
|
2016-05-15 06:36:42 +00:00
|
|
|
lastfile = ""
|
|
|
|
files = os.listdir(os.path.join("/home", user, ".ttbp", "entries"))
|
|
|
|
files.sort()
|
|
|
|
for filename in files:
|
|
|
|
if core.valid(filename):
|
|
|
|
lastfile = os.path.join("/home", user, ".ttbp", "entries", filename)
|
|
|
|
|
|
|
|
if lastfile:
|
|
|
|
last = os.path.getctime(lastfile)
|
2016-05-15 22:22:18 +00:00
|
|
|
timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(last))
|
2016-05-15 06:36:42 +00:00
|
|
|
else:
|
2016-05-15 22:22:18 +00:00
|
|
|
timestamp = ""
|
2016-05-15 06:36:42 +00:00
|
|
|
last = 0
|
|
|
|
|
2016-05-15 22:22:18 +00:00
|
|
|
userList.append(["<a href=\""+url+"\">~"+user+"</a> "+timestamp, last])
|
2016-05-15 06:36:42 +00:00
|
|
|
|
|
|
|
# sort user by most recent entry
|
|
|
|
userList.sort(key = lambda userdata:userdata[1])
|
|
|
|
userList.reverse()
|
|
|
|
sortedUsers = []
|
|
|
|
for user in userList:
|
|
|
|
sortedUsers.append(user[0])
|
|
|
|
|
|
|
|
core.write_global_feed(sortedUsers)
|
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
def list_select(options, prompt):
|
|
|
|
# runs the prompt for the list until a valid index is imputted
|
|
|
|
|
|
|
|
ans = ""
|
|
|
|
invalid = True
|
|
|
|
|
|
|
|
while invalid:
|
|
|
|
choice = raw_input("\n\n"+prompt)
|
2016-05-15 04:19:05 +00:00
|
|
|
|
2016-05-15 03:44:03 +00:00
|
|
|
if choice in BACKS:
|
|
|
|
return False
|
|
|
|
|
|
|
|
try:
|
|
|
|
ans = int(choice)
|
|
|
|
except ValueError:
|
|
|
|
return list_select(options, prompt)
|
|
|
|
|
|
|
|
invalid = False
|
|
|
|
|
|
|
|
if ans >= len(options):
|
|
|
|
return list_select(options, prompt)
|
|
|
|
|
|
|
|
return ans
|
|
|
|
|
2016-05-15 22:15:53 +00:00
|
|
|
def input_yn(query):
|
|
|
|
# returns boolean True or False
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
try:
|
|
|
|
ans = raw_input(query+" [y/n] ")
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
input_yn(query)
|
2016-05-15 22:15:53 +00:00
|
|
|
|
|
|
|
while ans not in ["y", "n"]:
|
|
|
|
ans = raw_input("'y' or 'n' please: ")
|
|
|
|
|
|
|
|
if ans == "y":
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def publishing(username = USER):
|
|
|
|
# checks .ttbprc for whether or not user wants their blog published online
|
|
|
|
|
|
|
|
ttbprc = {}
|
|
|
|
|
|
|
|
if username == USER:
|
|
|
|
ttbprc = SETTINGS
|
|
|
|
|
|
|
|
else:
|
|
|
|
ttbprc = json.load(open(os.path.join("/home", username, ".ttbp", "config", "ttbprc")))
|
|
|
|
|
|
|
|
return ttbprc.get("publishing")
|
|
|
|
|
|
|
|
def select_editor():
|
|
|
|
# setup helper for editor selection
|
|
|
|
|
|
|
|
print_menu(EDITORS)
|
|
|
|
choice = raw_input("\npick your favorite text editor: ")
|
2016-05-20 03:19:02 +00:00
|
|
|
while choice not in ['0', '1', '2', '3', '4', '5']:
|
2016-05-15 22:15:53 +00:00
|
|
|
choice = raw_input("\nplease pick a number from the list: ")
|
|
|
|
|
|
|
|
return EDITORS[int(choice)]
|
|
|
|
|
|
|
|
def select_publish_dir():
|
|
|
|
# setup helper for publish directory selection
|
|
|
|
|
2016-05-16 04:49:36 +00:00
|
|
|
current = SETTINGS.get("publish dir")
|
|
|
|
republish = False
|
|
|
|
|
|
|
|
if current:
|
2016-05-20 03:19:02 +00:00
|
|
|
print("\ncurrent publish dir:\t"+os.path.join(PUBLIC, SETTINGS["publish dir"]))
|
2016-05-16 04:49:36 +00:00
|
|
|
republish = True
|
|
|
|
|
2016-05-15 22:15:53 +00:00
|
|
|
choice = raw_input("\nwhere do you want your blog published? (leave blank to use default \"blog\") ")
|
|
|
|
if not choice:
|
|
|
|
choice = "blog"
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
publishDir = os.path.join(PUBLIC, choice)
|
|
|
|
while os.path.exists(publishDir):
|
2016-05-20 03:35:34 +00:00
|
|
|
second = raw_input("\n"+publishDir+"""\
|
|
|
|
already exists!
|
|
|
|
|
|
|
|
setting this as your publishing directory means this program may
|
|
|
|
delete or overwrite file there!
|
|
|
|
|
|
|
|
if you're sure you want to use it, hit <enter> to confirm.
|
|
|
|
otherwise, pick another location: """)
|
|
|
|
|
2016-05-15 22:15:53 +00:00
|
|
|
if second == "":
|
|
|
|
break
|
|
|
|
choice = second
|
2016-05-17 01:42:32 +00:00
|
|
|
publishDir = os.path.join(PUBLIC, choice)
|
2016-05-15 22:15:53 +00:00
|
|
|
|
|
|
|
return choice
|
|
|
|
|
|
|
|
def select_publishing():
|
|
|
|
# setup helper for toggling publishing
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
publish = input_yn("""\
|
2016-05-15 22:15:53 +00:00
|
|
|
do you want to publish your feels online?
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
if yes, your feels will be published to a directory of your choice in
|
|
|
|
your public_html. i'll confirm the location of that directory in a
|
|
|
|
moment.
|
|
|
|
|
|
|
|
if not, your feels will only be readable from within the tilde.town
|
|
|
|
network. if you already have a publishing directory, i'll remove it for
|
|
|
|
you (don't worry, your written entries will still be saved!)
|
2016-05-15 22:15:53 +00:00
|
|
|
|
|
|
|
you can change this option any time.
|
|
|
|
|
|
|
|
please enter\
|
|
|
|
""")
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
return publish
|
2016-05-16 04:49:36 +00:00
|
|
|
|
|
|
|
def unpublish():
|
|
|
|
# remove user's published directory, if it exists
|
2016-05-15 22:15:53 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
dir = SETTINGS.get("publish dir")
|
|
|
|
if dir:
|
|
|
|
publishDir = os.path.join(PUBLIC, dir)
|
|
|
|
subprocess.call(["rm", publishDir])
|
|
|
|
#subprocess.call(["rm", WWW])
|
2016-05-16 04:49:36 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
def update_publishing():
|
|
|
|
# handler to update publishing directory, or wipe it
|
2016-05-16 04:49:36 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
global SETTINGS
|
|
|
|
|
|
|
|
if publishing():
|
|
|
|
oldDir = SETTINGS.get("publish dir")
|
|
|
|
newDir = select_publish_dir()
|
|
|
|
SETTINGS.update({"publish dir": newDir})
|
|
|
|
if oldDir:
|
2016-05-20 03:35:34 +00:00
|
|
|
subprocess.call(["rm", os.path.join(PUBLIC, oldDir)])
|
2016-05-20 03:19:02 +00:00
|
|
|
make_publish_dir(newDir)
|
|
|
|
core.load_files()
|
|
|
|
core.write("index.html")
|
|
|
|
else:
|
|
|
|
unpublish()
|
|
|
|
SETTINGS.update({"publish dir": None})
|
2016-05-16 04:49:36 +00:00
|
|
|
|
|
|
|
def make_publish_dir(dir):
|
|
|
|
# setup helper to create publishing directory
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
if not os.path.exists(WWW):
|
|
|
|
subprocess.call(["mkdir", WWW])
|
|
|
|
subprocess.call(["ln", "-s", os.path.join(CONFIG, "style.css"), os.path.join(WWW, "style.css")])
|
|
|
|
subprocess.call(["touch", os.path.join(WWW, "index.html")])
|
|
|
|
index = open(os.path.join(WWW, "index.html"), "w")
|
2016-05-15 22:15:53 +00:00
|
|
|
index.write("<h1>ttbp blog placeholder</h1>")
|
|
|
|
index.close()
|
2016-05-17 01:42:32 +00:00
|
|
|
|
|
|
|
publishDir = os.path.join(PUBLIC, dir)
|
|
|
|
if os.path.exists(publishDir):
|
|
|
|
subprocess.call(["rm", publishDir])
|
|
|
|
|
|
|
|
subprocess.call(["ln", "-s", WWW, publishDir])
|
|
|
|
|
2016-05-15 22:15:53 +00:00
|
|
|
print("\n\tpublishing to "+LIVE+USER+"/"+SETTINGS.get("publish dir")+"/\n\n")
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
##### PATCHES
|
|
|
|
|
|
|
|
def updated():
|
|
|
|
# checks to see if current user is up to the same version as system
|
|
|
|
|
|
|
|
versionFile = os.path.join(PATH, "version")
|
|
|
|
if not os.path.exists(versionFile):
|
|
|
|
return False
|
|
|
|
|
|
|
|
ver = open(versionFile, "r").read()
|
|
|
|
|
|
|
|
if ver == VERSION:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
def update_version():
|
2016-05-20 03:19:02 +00:00
|
|
|
# updates user to current version
|
|
|
|
|
|
|
|
global SETTINGS
|
2016-05-17 01:42:32 +00:00
|
|
|
|
|
|
|
versionFile = os.path.join(PATH, "version")
|
2016-05-20 03:19:02 +00:00
|
|
|
|
|
|
|
print("ttbp had some updates!")
|
2016-05-17 01:42:32 +00:00
|
|
|
|
2016-05-20 15:06:42 +00:00
|
|
|
print("\ngive me a second to update you to version "+VERSION+"...\n")
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
print("...")
|
|
|
|
time.sleep(2)
|
2016-05-20 03:19:02 +00:00
|
|
|
|
2016-05-20 15:06:42 +00:00
|
|
|
if not os.path.isfile(versionFile):
|
|
|
|
# from 0.8.5 to 0.8.6:
|
2016-05-17 01:42:32 +00:00
|
|
|
|
|
|
|
# change style.css location
|
2016-05-20 03:19:02 +00:00
|
|
|
if os.path.isfile(os.path.join(WWW, "style.css")):
|
2016-05-17 01:42:32 +00:00
|
|
|
subprocess.call(["mv", os.path.join(WWW, "style.css"), CONFIG])
|
|
|
|
|
|
|
|
# change www symlink
|
|
|
|
if os.path.exists(WWW):
|
|
|
|
subprocess.call(["rm", WWW])
|
|
|
|
subprocess.call(["mkdir", WWW])
|
|
|
|
|
|
|
|
subprocess.call(["ln", "-s", os.path.join(CONFIG, "style.css"), os.path.join(WWW, "style.css")])
|
|
|
|
|
|
|
|
publishDir = os.path.join(PUBLIC, SETTINGS.get("publish dir"))
|
|
|
|
if os.path.exists(publishDir):
|
|
|
|
subprocess.call(["rm", "-rf", publishDir])
|
|
|
|
subprocess.call(["ln", "-s", WWW, os.path.join(PUBLIC, SETTINGS.get("publish dir"))])
|
|
|
|
|
|
|
|
# repopulate html files
|
|
|
|
core.load_files()
|
|
|
|
core.write("index.html")
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
# add publishing setting
|
|
|
|
print("\nnew feature!\n")
|
|
|
|
SETTINGS.update({"publishing":select_publishing()})
|
|
|
|
update_publishing()
|
2016-05-20 15:06:42 +00:00
|
|
|
ttbprc = open(TTBPRC, "w")
|
|
|
|
ttbprc.write(json.dumps(SETTINGS, sort_keys=True, indent=2, separators=(',',':')))
|
|
|
|
ttbprc.close()
|
|
|
|
|
|
|
|
else: # version at least 0.8.6
|
|
|
|
# from 0.8.6 to 0.8.7
|
|
|
|
if open(versionFile, 'r').read() == "0.8.6":
|
|
|
|
print("\nresetting your publishing settings...\n")
|
|
|
|
SETTINGS.update({"publishing":select_publishing()})
|
|
|
|
update_publishing()
|
|
|
|
ttbprc = open(TTBPRC, "w")
|
|
|
|
ttbprc.write(json.dumps(SETTINGS, sort_keys=True, indent=2, separators=(',',':')))
|
|
|
|
ttbprc.close()
|
2016-05-20 03:19:02 +00:00
|
|
|
|
|
|
|
|
2016-05-17 01:42:32 +00:00
|
|
|
# increment user versionfile
|
|
|
|
open(versionFile, "w").write(VERSION)
|
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
return "you're all good to go, "+chatter.say("friend")+"!\n"
|
2016-05-15 03:44:03 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
#####
|
2016-05-17 01:42:32 +00:00
|
|
|
|
2016-05-20 03:19:02 +00:00
|
|
|
start()
|
|
|
|
#print("ttbp beta is out to lunch. bbl.")
|