Added message privacy, currently 4 levels
This commit is contained in:
parent
09a8575068
commit
7700d4fa04
6 changed files with 651 additions and 9 deletions
94
app.py
94
app.py
|
|
@ -11,6 +11,8 @@ __version__ = '0.4-dev'
|
|||
app = Flask(__name__)
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
### DATABASE ###
|
||||
|
||||
database = SqliteDatabase(app.config['DATABASE'])
|
||||
|
||||
class BaseModel(Model):
|
||||
|
|
@ -73,9 +75,51 @@ class Message(BaseModel):
|
|||
# The text of the message.
|
||||
text = TextField()
|
||||
# Additional info (in JSON format)
|
||||
# TODO: remove because it's dumb.
|
||||
info = TextField(default='{}')
|
||||
# The posted date.
|
||||
pub_date = DateTimeField()
|
||||
# Info about privacy of the message.
|
||||
@property
|
||||
def privacy(self):
|
||||
try:
|
||||
return MessagePrivacy.get(MessagePrivacy.message == self).value
|
||||
except MessagePrivacy.DoesNotExist:
|
||||
# default to public
|
||||
return MSGPRV_PUBLIC
|
||||
def is_visible(self, is_public_timeline=False):
|
||||
user = self.user
|
||||
cur_user = get_current_user()
|
||||
privacy = self.privacy
|
||||
if user == cur_user:
|
||||
# short path
|
||||
return True
|
||||
elif privacy == MSGPRV_PUBLIC:
|
||||
return True
|
||||
elif privacy == MSGPRV_UNLISTED:
|
||||
# TODO user's posts may appear the same in public timeline,
|
||||
# even if unlisted
|
||||
return not is_public_timeline
|
||||
elif privacy == MSGPRV_FRIENDS:
|
||||
if cur_user is None:
|
||||
return False
|
||||
return user.is_following(cur_user) and cur_user.is_following(user)
|
||||
else:
|
||||
return False
|
||||
|
||||
# The message privacy values.
|
||||
MSGPRV_PUBLIC = 0 # everyone
|
||||
MSGPRV_UNLISTED = 1 # everyone, doesn't show up in public timeline
|
||||
MSGPRV_FRIENDS = 2 # only accounts which follow each other
|
||||
MSGPRV_ONLYME = 3 # only the poster
|
||||
|
||||
# Doing it into a separate table to don't worry about schema change.
|
||||
# Added in v0.4.
|
||||
class MessagePrivacy(BaseModel):
|
||||
# The message.
|
||||
message = ForeignKeyField(Message, primary_key=True)
|
||||
# The privacy value. Needs to be one of these above.
|
||||
value = IntegerField()
|
||||
|
||||
# this model contains two foreign keys to user -- it essentially allows us to
|
||||
# model a "many-to-many" relationship between users. by querying and joining
|
||||
|
|
@ -112,10 +156,13 @@ class Notification(BaseModel):
|
|||
|
||||
def create_tables():
|
||||
with database:
|
||||
database.create_tables([User, Message, Relationship, Upload, Notification])
|
||||
database.create_tables([
|
||||
User, Message, Relationship, Upload, Notification, MessagePrivacy])
|
||||
if not os.path.isdir(UPLOAD_DIRECTORY):
|
||||
os.makedirs(UPLOAD_DIRECTORY)
|
||||
|
||||
### UTILS ###
|
||||
|
||||
_forbidden_extensions = 'com net org txt'.split()
|
||||
_username_characters = frozenset(string.ascii_letters + string.digits + '_')
|
||||
|
||||
|
|
@ -180,6 +227,35 @@ def get_object_or_404(model, *expressions):
|
|||
except model.DoesNotExist:
|
||||
abort(404)
|
||||
|
||||
class Visibility(object):
|
||||
'''
|
||||
Workaround for the visibility problem for posts.
|
||||
Cannot be directly resolved with filter().
|
||||
|
||||
TODO find a better solution, this seems to be too slow.
|
||||
'''
|
||||
def __init__(self, query, is_public_timeline=False):
|
||||
self.query = query
|
||||
self.is_public_timeline = is_public_timeline
|
||||
def __iter__(self):
|
||||
for i in self.query:
|
||||
if i.is_visible(self.is_public_timeline):
|
||||
yield i
|
||||
def count(self):
|
||||
counter = 0
|
||||
for i in self.query:
|
||||
if i.is_visible(self.is_public_timeline):
|
||||
counter += 1
|
||||
return counter
|
||||
def paginate(self, page):
|
||||
counter = 0
|
||||
pages_no = range((page - 1) * 20, page * 20)
|
||||
for i in self.query:
|
||||
if i.is_visible(self.is_public_timeline):
|
||||
if counter in pages_no:
|
||||
yield i
|
||||
counter += 1
|
||||
|
||||
# flask provides a "session" object, which allows us to store information across
|
||||
# requests (stored by default in a secure cookie). this function allows us to
|
||||
# mark a user as being logged-in by setting some values in the session data:
|
||||
|
|
@ -267,22 +343,23 @@ def homepage():
|
|||
return render_template('homepage.html')
|
||||
|
||||
def private_timeline():
|
||||
# the private timeline exemplifies the use of a subquery -- we are asking for
|
||||
# the private timeline (aka feed) exemplifies the use of a subquery -- we are asking for
|
||||
# messages where the person who created the message is someone the current
|
||||
# user is following. these messages are then ordered newest-first.
|
||||
user = get_current_user()
|
||||
messages = (Message
|
||||
messages = Visibility(Message
|
||||
.select()
|
||||
.where((Message.user << user.following())
|
||||
| (Message.user == user))
|
||||
.order_by(Message.pub_date.desc()))
|
||||
# TODO change to "feed.html"
|
||||
return object_list('private_messages.html', messages, 'message_list')
|
||||
|
||||
@app.route('/explore/')
|
||||
def public_timeline():
|
||||
messages = (Message
|
||||
messages = Visibility(Message
|
||||
.select()
|
||||
.order_by(Message.pub_date.desc()))
|
||||
.order_by(Message.pub_date.desc()), True)
|
||||
return object_list('explore.html', messages, 'message_list')
|
||||
|
||||
@app.route('/signup/', methods=['GET', 'POST'])
|
||||
|
|
@ -345,7 +422,7 @@ def user_detail(username):
|
|||
# get all the users messages ordered newest-first -- note how we're accessing
|
||||
# the messages -- user.message_set. could also have written it as:
|
||||
# Message.select().where(Message.user == user)
|
||||
messages = user.messages.order_by(Message.pub_date.desc())
|
||||
messages = Visibility(user.messages.order_by(Message.pub_date.desc()), True)
|
||||
return object_list('user_detail.html', messages, 'message_list', user=user)
|
||||
|
||||
@app.route('/+<username>/follow/', methods=['POST'])
|
||||
|
|
@ -364,6 +441,7 @@ def user_follow(username):
|
|||
|
||||
flash('You are following %s' % user.username)
|
||||
push_notification('follow', user, user=cur_user.id)
|
||||
# TODO change to "profile.html"
|
||||
return redirect(url_for('user_detail', username=user.username))
|
||||
|
||||
@app.route('/+<username>/unfollow/', methods=['POST'])
|
||||
|
|
@ -392,6 +470,10 @@ def create():
|
|||
user=user,
|
||||
text=request.form['text'],
|
||||
pub_date=datetime.datetime.now())
|
||||
MessagePrivacy.create(
|
||||
message=message,
|
||||
value=request.form.get('privacy', '0')
|
||||
)
|
||||
file = request.files.get('file')
|
||||
if file:
|
||||
print('Uploading', file.filename)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue