Skip to content

Instantly share code, notes, and snippets.

@anumsh
Last active October 25, 2016 03:03
Show Gist options
  • Save anumsh/43d2a32dac9b4fb906afe1e4de796876 to your computer and use it in GitHub Desktop.
Save anumsh/43d2a32dac9b4fb906afe1e4de796876 to your computer and use it in GitHub Desktop.
multi-user blog.py file
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 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