Last active
October 25, 2016 03:03
-
-
Save anumsh/43d2a32dac9b4fb906afe1e4de796876 to your computer and use it in GitHub Desktop.
multi-user blog.py file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import re | |
import random | |
import hashlib | |
import hmac | |
from string import letters | |
import webapp2 | |
import jinja2 | |
from google.appengine.ext import db | |
template_dir = os.path.join(os.path.dirname(__file__), 'templates') | |
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), | |
autoescape = True) | |
secret = 'trumptrump' | |
def render_str(template, **params): | |
t = jinja_env.get_template(template) | |
return t.render(params) | |
def make_secure_val(val): | |
return '%s|%s' % (val, hmac.new(secret, val).hexdigest()) | |
def check_secure_val(secure_val): | |
val = secure_val.split('|')[0] | |
print "the check_secure_val val is "+val | |
if secure_val == make_secure_val(val): | |
return val | |
class BlogHandler(webapp2.RequestHandler): | |
def write(self, *a, **kw): | |
self.response.out.write(*a, **kw) | |
def render_str(self, template, **params): | |
params['user'] = self.user | |
return render_str(template, **params) | |
def render(self, template, **kw): | |
self.write(self.render_str(template, **kw)) | |
def set_secure_cookie(self, name, val): | |
cookie_val = make_secure_val(val) | |
print "the cookie value is "+cookie_val | |
self.response.headers.add_header( | |
'Set-Cookie', | |
'%s=%s; Path=/' % (name, cookie_val)) | |
def read_secure_cookie(self, name): | |
print "the name is read_secure_cookie"+ name | |
cookie_val = self.request.cookies.get(name) | |
print " the function read_secure_cookie-- cookie_val is "+ str(cookie_val) | |
return cookie_val and check_secure_val(cookie_val) | |
def login(self, user): | |
print "login user is "+ str(user) | |
self.set_secure_cookie('user_id', str(user.key().id())) | |
def logout(self): | |
self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/') | |
def initialize(self, *a, **kw): | |
webapp2.RequestHandler.initialize(self, *a, **kw) | |
uid = self.read_secure_cookie('user_id') | |
print "the uid is "+ str(uid) | |
self.user = uid and User.by_id(int(uid)) | |
def render_post(response, post): | |
response.out.write('<b>' + post.subject + '</b><br>') | |
response.out.write(post.content) | |
##### user stuff | |
def make_salt(length = 5): | |
return ''.join(random.choice(letters) for x in xrange(length)) | |
def make_pw_hash(name, pw, salt = None): | |
if not salt: | |
salt = make_salt() | |
h = hashlib.sha256(name + pw + salt).hexdigest() | |
return '%s,%s' % (salt, h) | |
def valid_pw(name, password, h): | |
salt = h.split(',')[0] | |
return h == make_pw_hash(name, password, salt) | |
def users_key(group = 'default'): | |
return db.Key.from_path('users', group) | |
class User(db.Model): | |
name = db.StringProperty(required = True) | |
pw_hash = db.StringProperty(required = True) | |
email = db.StringProperty() | |
@classmethod | |
def by_id(cls, uid): | |
print "the uid is of class method by_uid"+ str(uid) | |
return User.get_by_id(uid, parent = users_key()) | |
@classmethod | |
def by_name(cls, name): | |
u = User.all().filter('name =', name).get() | |
print "the class method ny name is "+ str(u) | |
return u | |
@classmethod | |
def register(cls, name, pw, email = None): | |
pw_hash = make_pw_hash(name, pw) | |
print "the register value of pw_hash is "+pw_hash | |
return User(parent = users_key(), | |
name = name, | |
pw_hash = pw_hash, | |
email = email) | |
@classmethod | |
def login(cls, name, pw): | |
u = cls.by_name(name) | |
print "login u value is "+ str(u) | |
if u and valid_pw(name, pw, u.pw_hash): | |
return u | |
##### blog stuff | |
def blog_key(name = 'default'): | |
return db.Key.from_path('blogs', name) | |
class Post(db.Model): | |
subject = db.StringProperty(required = True) | |
content = db.TextProperty(required = True) | |
created = db.DateTimeProperty(auto_now_add = True) | |
last_modified = db.DateTimeProperty(auto_now = True) | |
author = db.StringProperty(required=True) | |
likes = db.IntegerProperty(required=True) | |
liked_by = db.ListProperty(str) | |
def render(self): | |
self._render_text = self.content.replace('\n', '<br>') | |
return render_str("post.html", p = self) | |
def comments(self): | |
return Comment.all().filter("post = ", str(self.key().id())) | |
class Comment(db.Model): | |
comment = db.StringProperty(required=True) | |
post = db.StringProperty(required=True) | |
author = db.StringProperty(required=True) | |
@classmethod | |
def render(self): | |
self.render("comment.html") | |
class BlogFront(BlogHandler): | |
def get(self): | |
posts = greetings = Post.all().order('-created') | |
self.render('front.html', posts = posts) | |
class PostPage(BlogHandler): | |
def get(self, post_id): | |
key = db.Key.from_path('Post', int(post_id), parent=blog_key()) | |
post = db.get(key) | |
if not post: | |
self.error(404) | |
return | |
self.render("permalink.html", post = post) | |
class NewPost(BlogHandler): | |
def get(self): | |
if self.user: | |
self.render("newpost.html") | |
else: | |
self.redirect("/login") | |
def post(self): | |
if not self.user: | |
self.redirect('/login') | |
subject = self.request.get('subject') | |
content = self.request.get('content') | |
author = self.request.get('author') | |
if subject and content: | |
p = Post( | |
parent = blog_key(), | |
subject = subject, | |
content = content, | |
author = author, | |
likes = 0, | |
liked_by = []) | |
p.put() | |
self.redirect('/blog/%s' % str(p.key().id())) | |
else: | |
error = "please fill the both subject and content!" | |
self.render("newpost.html", subject=subject, content=content, error=error) | |
class EditPost(BlogHandler): | |
def get(self): | |
if self.user: | |
post_id = self.request.get("post") | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
if not post: | |
self.error(404) | |
return | |
if self.user.name == post.author: | |
self.render( | |
"editpost.html", | |
subject=post.subject, | |
content=post.content) | |
else: | |
self.redirect("/error") | |
def post(self): | |
if self.user: | |
post_id = self.request.get("post") | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
subject = self.request.get("subject") | |
content = self.request.get("content") | |
if subject and content: | |
post.subject = subject | |
post.content = content | |
post.put() | |
self.redirect("/blog/%s" % str(post.key().id())) | |
else: | |
error = "Please fill in both a subject and content." | |
self.render( | |
"editpost.html", | |
subject=sucject, | |
content=content, | |
error="error") | |
else: | |
self.redirect("/login") | |
class DeletePost(BlogHandler): | |
def get(self): | |
if self.user: | |
post_id = self.request.get("post") | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
if not post: | |
self.error(404) | |
return | |
if self.user.name == post.author: | |
self.render("deletepost.html", post=post) | |
else: | |
self.redirect("/login") | |
def post(self): | |
if self.user: | |
post_id = self.request.get("post") | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
if post and post.author == self.user.name: | |
post.delete() | |
self.render("successfully-deleted.html") | |
else: | |
self.redirect("/login") | |
class NewComment(BlogHandler): | |
def get(self): | |
if not self.user: | |
return self.redirect("/login") | |
post_id = self.request.get("post") | |
post = Post.get_by_id(int(post_id), parent=blog_key()) | |
subject = post.subject | |
content = post.content | |
self.render( | |
"newcomment.html", | |
subject=subject, | |
content=content, | |
pkey=post.key()) | |
def post(self): | |
if self.user: | |
post_id = self.request.get("post") | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
if not post: | |
self.error(404) | |
return | |
if not self.user: | |
return self.redirect("login") | |
comment = self.request.get("comment") | |
if comment: | |
# check how author was defined | |
author = self.request.get("author") | |
c = Comment( | |
comment=comment, | |
post=post_id, | |
parent=self.user.key(), | |
author=author) | |
c.put() | |
self.redirect("/blog/%s" % str(post_id)) | |
else: | |
error = "please comment" | |
self.render( | |
"permalink.html", | |
post=post, | |
content=content, | |
error=error) | |
else: | |
self.redirect("/login") | |
class EditComment(BlogHandler): | |
def get(self, post_id, comment_id): | |
if self.user: | |
post = Post.get_by_id(int(post_id), parent=blog_key()) | |
comment = Comment.get_by_id( | |
int(comment_id), parent=self.user.key()) | |
if comment: | |
self.render("editcomment.html", subject=post.subject, | |
content=post.content, comment=comment.comment) | |
else: | |
self.redirect("/error") | |
else: | |
self.redirect("/login") | |
def post(self, post_id, comment_id): | |
if self.user: | |
comment = Comment.get_by_id( | |
int(comment_id), parent=self.user.key()) | |
if comment.parent().key().id() == self.user.key().id(): | |
comment_temp = self.request.get("comment") | |
if comment_temp: | |
comment.comment = comment_temp | |
comment.put() | |
# TODO: Should show an updated comment | |
self.redirect("/blog/%s" % str(post_id)) | |
else: | |
error = "Please fill in comment." | |
self.render( | |
"editcomment.html", | |
subject=post.subject, | |
content=post.content, | |
comment=comment.comment) | |
else: | |
self.redirect("/login") | |
class DeleteComment(BlogHandler): | |
def get(self, post_id, comment_id): | |
if self.user: | |
post = Post.get_by_id(int(post_id), parent=blog_key()) | |
comment = Comment.get_by_id( | |
int(comment_id), parent=self.user.key()) | |
if comment: | |
self.render("deletecomment.html", subject=post.subject, | |
content=post.content, comment=comment.comment) | |
else: | |
self.redirect("/error") | |
else: | |
self.redirect("/login") | |
def post(self, post_id, comment_id): | |
if self.user: | |
post = Post.get_by_id(int(post_id), parent=blog_key()) | |
comment = Comment.get_by_id( | |
int(comment_id), parent=self.user.key()) | |
if comment.author == self.user.name: | |
comment.delete() | |
self.redirect("/blog/%s" % str(post_id)) | |
else: | |
self.write("Sorry, something went wrong..") | |
else: | |
self.redirect("/login") | |
class LikePost(BlogHandler): | |
def get(self, post_id): | |
if not self.user: | |
self.redirect("/login") | |
else: | |
key = db.Key.from_path("Post", int(post_id), parent=blog_key()) | |
post = db.get(key) | |
author = post.author | |
logged_user = self.user.name | |
if author == logged_user or logged_user in post.liked_by: | |
self.redirect("/error") | |
else: | |
post.likes += 1 | |
post.liked_by.append(logged_user) | |
post.put() | |
self.redirect("/blog") | |
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$") | |
def valid_username(username): | |
return username and USER_RE.match(username) | |
PASS_RE = re.compile(r"^.{3,20}$") | |
def valid_password(password): | |
return password and PASS_RE.match(password) | |
EMAIL_RE = re.compile(r'^[\S]+@[\S]+\.[\S]+$') | |
def valid_email(email): | |
return not email or EMAIL_RE.match(email) | |
class Signup(BlogHandler): | |
def get(self): | |
self.render("signup-form.html") | |
def post(self): | |
have_error = False | |
self.username = self.request.get('username') | |
self.password = self.request.get('password') | |
self.verify = self.request.get('verify') | |
self.email = self.request.get('email') | |
params = dict(username = self.username, | |
email = self.email) | |
if not valid_username(self.username): | |
params['error_username'] = "That's not a valid username." | |
have_error = True | |
if not valid_password(self.password): | |
params['error_password'] = "That wasn't a valid password." | |
have_error = True | |
elif self.password != self.verify: | |
params['error_verify'] = "Your passwords didn't match." | |
have_error = True | |
if not valid_email(self.email): | |
params['error_email'] = "That's not a valid email." | |
have_error = True | |
if have_error: | |
self.render('signup-form.html', **params) | |
else: | |
self.done() | |
def done(self, *a, **kw): | |
raise NotImplementedError | |
''' | |
class Unit2Signup(Signup): | |
def done(self): | |
self.redirect('/unit2/welcome?username=' + self.username) | |
''' | |
class Register(Signup): | |
def done(self): | |
#make sure the user doesn't already exist | |
u = User.by_name(self.username) | |
if u: | |
msg = 'That user already exists.' | |
self.render('signup-form.html', error_username = msg) | |
else: | |
u = User.register(self.username, self.password, self.email) | |
u.put() | |
self.login(u) | |
self.redirect('/blog') | |
class Login(BlogHandler): | |
def get(self): | |
self.render('login-form.html') | |
def post(self): | |
username = self.request.get('username') | |
password = self.request.get('password') | |
u = User.login(username, password) | |
if u: | |
self.login(u) | |
self.redirect('/blog') | |
else: | |
msg = 'Invalid login' | |
self.render('login-form.html', error = msg) | |
class Logout(BlogHandler): | |
def get(self): | |
self.logout() | |
self.redirect('/blog') | |
class Unit3Welcome(BlogHandler): | |
def get(self): | |
if self.user: | |
self.render('welcome.html', username = self.user.name) | |
else: | |
self.redirect('/signup') | |
class Welcome(BlogHandler): | |
def get(self): | |
username = self.request.get('username') | |
if valid_username(username): | |
self.render('welcome.html', username = username) | |
else: | |
self.redirect('/unit2/signup') | |
app = webapp2.WSGIApplication([('/', BlogFront), | |
('/unit2/signup', Signup), | |
('/unit2/welcome', Welcome), | |
('/blog/?', BlogFront), | |
('/blog/([0-9]+)', PostPage), | |
('/blog/newpost', NewPost), | |
('/blog/editpost', EditPost), | |
('/blog/deletepost', DeletePost), | |
("/blog/newcomment", NewComment), | |
("/blog/([0-9]+)/editcomment/([0-9]+)",EditComment), | |
("/blog/([0-9]+)/deletecomment/([0-9]+)",DeleteComment), | |
("/blog/([0-9]+)/like", LikePost), | |
('/signup', Register), | |
('/login', Login), | |
('/logout', Logout), | |
('/unit3/welcome', Unit3Welcome), | |
], | |
debug=True) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- this is html for the front of the blog . base.html is the template inheritance ( | |
we donot have to write the html over and over again) --> | |
{% extends "base.html" %} | |
{% block content %} | |
<div class="new-post"> | |
<a href="/blog/newpost">NEW POST</a> | |
</div> | |
{% for post in posts %} | |
{{ post.render() | safe}} | |
<br> | |
<br> | |
{% if user.name == post.author %} | |
<a class="edit-link btn btn-primary" href="/blog/editpost?post={{post.key().id()}}">Edit</a> | |
<a class="edit-link btn btn-primary" href="/blog/delete?post={{post.key().id()}}">Delete</a> | |
{% else %} | |
<a href="/blog/{{post.key().id()}}/like">Like</a> | |
{% endif %} | |
{% if user and post.comments %} | |
<div> | |
<span>{{post._num_comments}} comments</span> | |
</div> | |
<div class="post-comments"> | |
<h3 class="comment-title">Comments</h3> | |
{% for c in post.comments %} | |
<div class="comments"> | |
<div class="comment-author"> from : {{c.parent().name }} </div> | |
<p class="comment-content">{{c.comment}}</p> | |
{% if user.name == c.author %} | |
<a href="/blog/{{post.key().id()}}/editcomment/{{c.key().id()}}" class="btn btn-default btn-xs">Edit comment</a> | |
<a href="/blog/{{post.key().id()}}/deletecomment/{{c.key().id()}}" class="btn btn-default btn-xs">Delete comment</a> | |
{% endif %} | |
</div> | |
{% endfor %} | |
<a href="/blog/newcomment?post={{post.key().id()}}" class="btn btn-default btn-xs">Add New Comment </a> | |
</div> | |
{% endif %} | |
{% endfor %} | |
{% endblock %} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment