DanielVasicek / Udacity

WikiWeb Page for Udacity Class

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Udacity Final Exam "wiki"
import re, os
import cgi
import webapp2
import random
import string
import datetime
import hashlib, hmac
from google.appengine.ext import db
secret = 'MTzgl2cRLFchZ2bhqGCZFovuWPBCUcfQEiLtl8eh'

USER_RE  = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
PWD_RE   = re.compile(r"^.{3,20}$")
EMAIL_RE = re.compile(r"^[\S]+@[\S]+\.[\S]+$")
	
form1 ="""<html><head> <title>Vasicek Wiki</title></head></head><body>"""
form2="""<form method = "post">><textarea name ="content" >"""

form6="""</textarea> <br> </form></body></html>"""
form6a="""</body></html>"""
form5 = """</textarea> <br><input type="submit"> </form></body></html>"""
form="""
<form method = "post">
   <b> Please input your desired username, password, and email address.</b>  
   The username must be 3-20 alphanumeric characters and may include -_.  The password can be 3-20 of any characters and the verification password must match the original password. <br>
   <table>
   <tr>
   <td>Username</td>
   <td><input type="text" name ="username" value ="%(username)s"> </td>
   <td>%(username_error)s</td></tr>
   <tr>
   <td>Password</td>
   <td><input type="password" name ="password"   value ="%(password)s"> </td>
   <td>%(password_error)s</td></tr>
   <tr>
   <td>Verification Password</td>
   <td><input type="password" name ="verify"     value ="%(verify)s"></td>
   <td>%(verify_error)s</td></tr>
   <tr>
   <td>Email Address</td>
   <td><input type="text" name ="email" value ="%(email)s"></td>
   <td>%(email_error)s</td></tr></table>
 
    <br><br> <input type="submit">
</form>
"""
wid=''
web_pre=''
old_content=''
lform="""
<form method = "post">
   <b> Please input your username, and password</b> 
   <table>
   <tr>
   <td>Username</td>
   <td><input type="text" name ="username" value ="%(username)s"> </td></tr>
   <tr>
   <td>Password</td>
   <td><input type="password" name ="password"   value ="%(password)s"> </td>
   </tr>
   </table>
   <br> %(error)s
 
    <br><br> <input type="submit"></form>
    """

def datetime2str(dt):
	year   =str(getattr(dt,'year'))
	month  =str(getattr(dt,'month'))
	day    =str(getattr(dt,'day'))
	hour   =str(getattr(dt,'hour'))
	minute =str(getattr(dt,'minute'))
	second =str(getattr(dt,'second'))
	ms     =str(getattr(dt,'microsecond'))
	return year+':'+month+':'+day+':'+hour+':'+minute+':'+second+':'+ ms
def str2datetime(dt):
	s=dt.split(':')
	return datetime.datetime(int(s[0]),int(s[1]),int(s[2]),int(s[3]),int(s[4]),int(s[5]),int(s[6]))

			
def make_secure_val(val):
	return '%s|%s' % (val, hmac.new(secret, val).hexdigest())
def check_secure_val(secure_val):
	# check that the hash val and val are consistent
	val = secure_val.split('|')[0]
	if secure_val == make_secure_val(val):
		return val

def escape_html(s):
	return cgi.escape(s, quote = True)

def valid_username(username):
	if USER_RE.match(username):
		return username
	else:
		return ""
    
def valid_password(password):
	if PWD_RE.match(password):
		return password
	else:
		return ""
	  
def valid_email(email):
	if EMAIL_RE.match(email):
                return str(email)

def make_salt(length=5):
    return ''.join(random.choice(string.letters) for x in range(length))

def make_pw_hash(name, pw, salt = None ):
	if not salt:
		salt = make_salt()
        h = hashlib.sha256(str(name) + pw + salt).hexdigest()
    	return '%s|%s' % (h, salt)

def valid_pw(name, pw, hh):
    [h,salt]=hh.split('|')
    return h == make_pw_hash(name, pw, salt)

def users_key(group= 'default'):
    return db.Key.from_path('users', group)

def count_db_results(d):
    l=0
    for b in d:
    	l+=1
    return l

def set_secure_cookie( self, name, val): 
    cookie_val = make_secure_val(val)
    self.response.headers.add_header(
			'Set-Cookie',
			'%s=%s; Path=/' % (name, cookie_val))

def read_secure_cookie(self,  name):
	cookie_val = self.request.cookies.get(name)
	return cookie_val and check_secure_val(cookie_val)

def login(self, user):
	self.set_secure_cookie('username', str(user.key().id()))

def logout(self):
	self.response.headers.add_header('Set-Cookie', 'username=; Path=/')

def initialize(self, *a, **kw):
	webapp2.RequestHandler.initialize(self, *a, **kw)
	uid = self.read_secure_cookie('username')
	self.user = uid and User.by_id(int(uid))

class Pages(db.Model):
	loc     =db.StringProperty  (required     = True)
	content =db.TextProperty    (required     = True)
	user    =db.StringProperty  (required     = True)
	created =db.DateTimeProperty(auto_now_add = True)
	modified=db.DateTimeProperty(auto_now     = True)

    
class User(db.Model):
	username=db.StringProperty (required=True)
	password=db.StringProperty (required=True)
	created =db.DateTimeProperty(auto_now_add = True)
	# email   =db.EmailProperty()
	email   =db.StringProperty()

	@classmethod
	def by_name(cls, name):
		u = User.all().filter('name =', name).get()
		return u

	@classmethod
	def by_id(cls, uid):
		return User.get_by_id(uid, parent = users_key())

	@classmethod
	def register(cls, name, pw, email = None):
		pw_hash = make_pw_hash(name, pw)
		return User(parent = users_key(),
				name    = name,
				pw_hash = pw_hash,
				email   = email)


	@classmethod
	def login(cls, name, pw):
		u = cls.by_name(name)
		if u and valid_pw(name, pw, u.pw_hash):
			return u

class Signup(webapp2.RequestHandler):
    def set_secure_cookie( self, name, val): 
   	 cookie_val = str(make_secure_val(val))
    	 self.response.headers.add_header(
			'Set-Cookie',
			'%s=%s; Path=/' %(name, cookie_val))

    def read_secure_cookie(self,  name):
	cookie_val = self.request.cookies.get(name)
	return cookie_val and check_secure_val(cookie_val)
    userid=''
    useridc=''
    id=0
    def write_form(self,username="", username_error="", password="",password_error="", verify  ="", verify_error  ="", email   ="",email_error   ="" ):
	# self.response.headers['Content-Type'] = 'text/plain'   
    	self.response.out.write(form % { "username"       : escape_html(username), 
		                         "username_error" : username_error,         
				         "password"       : escape_html(password),  
					 "password_error" : password_error,          
				         "verify"         : escape_html(verify),
					 "verify_error"   : verify_error, 
	                                 "email"          : escape_html(email),
					 "email_error"    : email_error})


    def get(self):
		self.write_form(username="", username_error="", password='', password_error="", verify='', verify_error='', email='', email_error='')

    def post(self):	    
	user_username   = escape_html(self.request.get('username'))
        user_password   = escape_html(self.request.get('password'))
	user_verify     = escape_html(self.request.get('verify'  ))
	user_email      = escape_html(self.request.get('email'   ))
	username        = str(valid_username(user_username))
        password        = str(valid_password(user_password))
	verify          = str(valid_password(user_verify))
	email           = str(valid_email(user_email))
	# self.response.headers['Content-Type'] = 'text/plain'
	# usernamehash =self.request.cookies.get('usernamehash','')
	# usernamec    =self.request.cookies.get('username','')
	anerror=False
	username_error=''
	password_error=''
	verify_error=''
	email_error=''
	if (username == '' ):
		username_error='Please select a valid username.'
		anerror = True
	if not (anerror):
		uids=db.GqlQuery("select * from User where username = '%s' " % username)
		if count_db_results(uids) >0 :
			username_error='That username is already taken!'
			anerror =True
		else:
			if not(valid_username(username)):
				username_error='Please select a valid username.'
				anerror=True

	if (password == '' ):
		password_error='Please select a valid password.'
		anerror = True
	if not(password == verify):
		verify_error='The verification password must match the password.'
		password=''
		verify=''
		anerror = True
	if not(user_email =='') and not(email == user_email):
		email_error='Please select a valid email address.'
		anerror=True
	if anerror:
		self.write_form(user_username, username_error,
				user_password, password_error, 
				user_verify,   verify_error,
				user_email,    email_error)
	else:
		
		a=User(username=username, password=password, email=email)
		a.put()
		id=a.key().id()

		set_secure_cookie(self, 'user_id',str(id))
		set_secure_cookie(self, 'username',str(username))

		self.redirect(web_pre+wid)


class Logout(Signup):
	def get(self):
		self.response.headers.add_header('Set-Cookie', 'username=; Path=/')
		self.redirect(web_pre+wid)

class Login(Signup):
	def get(self):
		blank =''
		self.response.out.write(lform % { "username"       : blank,
						  "password"       : blank,
				                  "error"          : blank})

	def post(self):
		username = self.request.get('username')
		password = self.request.get('password')
                #  u = User.login(username, password)
		users = db.GqlQuery("Select * from User")
		l=0
		u=None
		found=False
		for b in users:
			l=l+1
			u=b
			if str(b.username) == str(username) and str(b.password) == str(password):
				u=b
				found=True
				break


		if  found :
			set_secure_cookie(self, 'username',str(username))
			self.redirect(web_pre+wid)
		else:
			msg="Invalid Login  username =" + username + " password = " + password + "  up=" + str(l)
			username=""
			password =""
			self.response.out.write(lform % { "username"       : escape_html(username),
							  "password"       : escape_html(password),
				                          "error"          : msg})
class Inventory(Signup):
	def get(self):
		t1="""<form method = "post">
   <b>Table of usernames and passwords</b> 
   <table>
		"""

		users = db.GqlQuery("Select * from User order by created desc")
		t2='<tr> <td>Username</td> <td>Password</td></tr>'
		for u in users:
			t2 = t2+ '<tr><td> ' + str(u.username)+ '</td><td>' +  str(u.password) + '</td></tr>'

		self.response.out.write(t1+t2 + '</table> </form>' )

	def post(self):
		username = self.request.get('username')
		password = self.request.get('password')
                #  u = User.login(username, password)
		users = db.GqlQuery("Select * from User")
		l=0
		for b in users:
			l=l+1
			u=b
			if str(b.username) == str(username) and str(b.password) == str(password):
				u=b
				break

class Blogsummary(Signup):
	def get(self):
		posts = db.GqlQuery("Select * from Blogs order by created desc limit 10")
		t1= """<form method = "post"> <b>Table of 10 most recent Subjects and Blogs</b><br>"""
		body=''
		for p in posts:
			body = body+ 'Subject: <br>' + p.subject +'<br> Content:<br> ' + p.content + '<br> ---'+str(p.modified) +'---------------- <br>'
		self.response.out.write(t1+body + '''<br><a href='/blogs/newpost'>Add a new blog</a> </form>''' )


class WikiPage(webapp2.RequestHandler):
	# to generate wiki pages. DJV  Create a bootstrap:
	def get(self, id):
		global wid, web_pre
		web_pre=''
		wid=str(id)
		m=None
		m1=self.request.get('m')
		m=m1.split(':')
		username1     = self.request.cookies.get('username','')
		username      = read_secure_cookie(self,  'username')
		if username:
			thtml="""<a href='_edit""" + wid + """'> edit</a> |  <a href='_history""" + wid + """'> history</a> """ + username + """          | <a href='/logout'> logout</a>"""
		else:
			thtml="""                                            <a href='_history""" + wid + """'> history</a>  <a href='/login'> login</a>| <a href='/signup'> signup</a>"""
		if len(m) >4 :
			po = db.GqlQuery("""Select * from Pages where loc ='""" + wid+ """'order by modified desc """)
			pp=None
			for p in po:
				x=datetime2str(p.modified).split(':')
				deltat=0
				for i in range(6):
					deltat=deltat+abs(int(m[i])-int(x[i]))
				if deltat==0:
					pp=p						
					break
		else:
			post = db.GqlQuery("""Select * from Pages where loc ='""" + wid+ """'   order by modified desc limit 2""")
			pp=None
			for p in post:
				pp=p
				break

		
		if pp:
			#self.response.out.write(form1 + thtml + form2+pp.content + form6)
			self.response.out.write(form1+thtml+'<br>'+ pp.content +form6a)
		else:
			if username:
				web_pre='/_edit'
				self.redirect('/_edit'+wid)
			else:
				self.response.out.write("""There is no such page and you must be logged in to create a page.  <a href='/login'> login</a>| <a href='/signup'> signup</a>""")


class IPages(WikiPage):
	def get(self):
		pages=db.GqlQuery("""Select * from Pages order by modified desc""")
		d='<html><body><h1>Inventory Pages</h1><br> ----- Date Modified -------------- Location  ----- content ------ username <br>'
		for p in pages:
			d=d+str(p.modified) + """ ---- <a href='""" + str(p.loc)+ """'> """ + str(p.loc) + '</a> --- '+ str(p.content) + ' ---- ' +  str(p.user) +' <br>'
		d=d+'</body></html>'

		self.response.out.write(d)

class IUsers(Signup):
	def get(self):
		self.response.out.write('Inventory Users')

class EditPage(WikiPage):
	def get(self, id):
		global web_pre, wid, old_content
		username      = read_secure_cookie(self,  'username')
		if username:
			web_pre='/_edit'
			wid=str(id)
			m1=self.request.get('m')
			m=m1.split(':')
			
	

			thtml= username + """          | <a href='/logout'> logout</a>"""
			pp=None
			if len(m)>4:
				po = db.GqlQuery("""Select * from Pages where loc ='""" + wid+ """'order by modified desc """)
				for p in po:
					x=datetime2str(p.modified).split(':')
					deltat=0
					for i in range(6):
						deltat=deltat+abs(int(m[i])-int(x[i]))
					if deltat==0:
						pp=p						
						break
				
			else:
				po = db.GqlQuery("""Select * from Pages where loc ='""" + wid+ """'order by modified desc limit 2 """)
				for p in po:
					pp=p
					break
				
				
			if pp:
				self.response.out.write(form1 + thtml + form2+escape_html(pp.content) + form5)
				old_content=pp.content
			else:
				self.response.out.write(form1 + thtml + form2 + form5)
	
		else:
			self.redirect('/login')
	
	def post(self,id):
		content=self.request.get("content")
		username = read_secure_cookie(self,  'username')
		if username=='':
			self.error(400)
			return
		if content=='' or (content== old_content):
			return


		a=Pages(loc=str(wid), content= content, user=username)
		a.put()
		self.redirect(wid)


		
class HistoryPage(WikiPage):
	def get(self,id):
		global web_pre, wid
		web_pre='/_history'
		wid=str(id)
		username      = read_secure_cookie(self,  'username')
		if username:
			thtml="""<a href='/_edit""" + wid + """'> edit most recent</a> |  <a href='""" + wid + """'> view most recent | </a> """ + username + """  | <a href='/logout'> logout</a>"""
		else:
			thtml="""<a href='/"""      + wid + """'> view most recent</a> | <a href='/login'> login</a> | <a href='/signup'> signup</a>"""
		po = db.GqlQuery("""Select * from Pages where loc ='""" + wid+ """'   order by modified desc""")
		l=0
		d='<html><title>History Wiki</title><body>' + thtml + '<br> <table>'
		for p in po:
			l=l+1
			s3=datetime2str(p.modified)
			s=escape_html(p.content)
			ss=s
			if len(s)>50:
				ss=s[0:49]


			d=d+"<tr><td>"+ s3+'</td><td>' + ss+ """</td> <td><a href='""" + wid+"""?m="""+s3+"""' >view</a> </td><td> <a href='/_edit""" + wid + """?m=""" +s3 + """'> edit</a></td></tr>"""


		self.response.out.write( d +"</table></body></html>")







PAGE_RE = r'(/(?:[a-zA-Z0-9_-]+/?)*)'
app = webapp2.WSGIApplication([('/signup', Signup),
                               ('/login', Login),
                               ('/logout', Logout),
			       ('/inventory', Inventory),
			       ('/inventory_pages',IPages),
			       ('/inventory_users',IUsers),
                               ('/_edit' + PAGE_RE, EditPage),
                               ('/_history' + PAGE_RE, HistoryPage),
                               (PAGE_RE, WikiPage)
                               ], debug=True)

About

WikiWeb Page for Udacity Class