Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: saurya/minigiant
base: 4abbb695eb
...
head fork: saurya/minigiant
compare: 698ad952bf
  • 1 commit
  • 14 files changed
  • 0 commit comments
  • 1 contributor
Commits on Oct 19, 2012
@saurya Trimming shit down 698ad95
View
57 addfriend.py
@@ -0,0 +1,57 @@
+import os
+import cgi
+import common
+import datetime
+import re
+import models
+import webapp2
+
+from google.appengine.ext import db
+from google.appengine.api import mail
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+FRIEND_NICK_PARAM = "f"
+USER_ID_PARAM = "u"
+ADD_FN = "addFriend"
+
+class AddFriendHandler(webapp2.RequestHandler):
+ def emailFriend(self, friend):
+ mail.send_mail(sender="saurya@gmail.com",
+ to=friend.nickname() + " <" + friend.email() + ">",
+ subject="A friend wants to challenge you to workout!",
+ body="""
+ Hey there!
+
+ Head on over to http://omarvssaurya.appspot.com and track your workouts!
+ One of your friends, who has already been using it, wants to challenge you.
+
+ The way it works: you can track your own workouts. Add friends, to see how
+ they're doing and compete with them!
+
+ Cheers,
+ The Workout Challenge Team
+ """)
+
+ def get(self):
+ user_id = self.request.get(USER_ID_PARAM)
+ parent_key = db.Key.from_path("User", user_id)
+ contest = models.Contest().all().ancestor(parent_key).get()
+ friend = users.User(self.request.get(FRIEND_NICK_PARAM))
+ if contest and friend not in contest.participants:
+ contest.participants.append(friend)
+ contest.put()
+ friend_contest = models.Contest().all().filter('user =', friend).get()
+ if not friend_contest:
+ self.emailFriend(friend)
+ else:
+ friend = friend_contest.user
+ # Render JSONP Response
+ path = os.path.join(os.path.dirname(__file__), 'scorecard.html')
+ self.response.headers['Content-Type'] = 'applicaton/javascript'
+ self.response.out.write(ADD_FN + "('" + common.renderDays(friend, path) + "')")
+
+app = webapp2.WSGIApplication([
+ ('/addfriend', AddFriendHandler)
+], debug=True)
View
25 app.yaml
@@ -0,0 +1,25 @@
+application: omarvssaurya
+version: 1
+runtime: python27
+api_version: 1
+threadsafe: yes
+handlers:
+- url: /favicon\.ico
+ static_files: favicon.ico
+ upload: favicon\.ico
+
+- url: /log
+ script: log.app
+- url: /delete
+ script: delete.app
+- url: /addfriend
+ script: addfriend.app
+- url: /deletefriend
+ script: deletefriend.app
+- url: .*
+ script: main.app
+
+
+libraries:
+- name: webapp2
+ version: "2.5.1"
View
53 common.py
@@ -0,0 +1,53 @@
+import models
+import os
+import datetime
+from google.appengine.ext import db
+from google.appengine.ext.webapp import template
+
+class Record(list):
+ pass
+
+# returns a tuple of (score, entries_by_date)
+def getDays(user):
+ your_score = 0
+ index = -1
+ date = []
+ yourdays = Record()
+ # run the query to get all entries for this user
+ parent_key = db.Key.from_path("User", user.user_id())
+ entries = models.Entry().all()
+ entries.ancestor(parent_key)
+ entries.order('-date')
+ your_entries = entries.run()
+ for entry in your_entries:
+ if date != entry.date.date():
+ date = entry.date.date()
+ day = Record()
+ day.date = date
+ yourdays.append(day)
+ index += 1
+ your_score += entry.points
+ yourdays[index].append(entry)
+ yourdays.name = user.nickname().split("@")[0]
+ yourdays.score = your_score
+ yourdays.nickname = user.nickname()
+ return yourdays
+
+def renderDays(user, path):
+ yourdays = getDays(user)
+ today = Record()
+ today.date = datetime.datetime.now().date()
+ if len(yourdays) == 0 or yourdays[0].date != today.date:
+ yourdays.insert(0, today)
+ template_values = {
+ 'yourdays' : yourdays
+ }
+ return template.render(path, template_values)
+
+def getCompetitors(user):
+ contest = models.Contest.all()
+ contest.filter('user =', user)
+ user_contest = contest.get()
+ if user_contest:
+ return user_contest.participants
+ return []
View
26 delete.py
@@ -0,0 +1,26 @@
+import os
+import cgi
+import datetime
+import re
+import models
+import webapp2
+
+from google.appengine.ext import db
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+ENTRY_ID_PARAM = "e"
+USER_ID_PARAM = "u"
+
+class DeleteHandler(webapp2.RequestHandler):
+ def get(self):
+ user_id = self.request.get(USER_ID_PARAM)
+ key = self.request.get(ENTRY_ID_PARAM)
+ entry = models.Entry(key=key)
+ db.delete(entry)
+
+
+app = webapp2.WSGIApplication([
+ ('/delete', DeleteHandler)
+], debug=True)
View
28 deletefriend.py
@@ -0,0 +1,28 @@
+import os
+import cgi
+import datetime
+import re
+import models
+import webapp2
+
+from google.appengine.ext import db
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+FRIEND_NICK_PARAM = "f"
+USER_ID_PARAM = "u"
+
+class DeleteFriendHandler(webapp2.RequestHandler):
+ def get(self):
+ user_id = self.request.get(USER_ID_PARAM)
+ parent_key = db.Key.from_path("User", user_id)
+ contest = models.Contest().all().ancestor(parent_key).get()
+ friend = users.User(self.request.get(FRIEND_NICK_PARAM))
+ if contest and friend in contest.participants:
+ contest.participants.remove(friend)
+ contest.put()
+
+app = webapp2.WSGIApplication([
+ ('/deletefriend', DeleteFriendHandler)
+], debug=True)
View
BIN  favicon.ico
Binary file not shown
View
17 index.yaml
@@ -0,0 +1,17 @@
+indexes:
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run. If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED"). If you want to manage some indexes
+# manually, move them above the marker line. The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+
+- kind: Entry
+ ancestor: yes
+ properties:
+ - name: date
+ direction: desc
View
51 log.py
@@ -0,0 +1,51 @@
+import os
+import cgi
+import datetime
+import re
+import models
+import webapp2
+
+from google.appengine.ext import db
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+QUERY_CGI_PARAM = "q"
+USER_ID_PARAM = "u"
+ADD_FN = "addNewEntry"
+
+class LogHandler(webapp2.RequestHandler):
+ def getExerciseName(self, query):
+ words = [s for s in query.split() if not s.isdigit()]
+ return words[0]
+
+ def getExercise(self, query):
+ return models.exercises[self.getExerciseName(query)]
+
+ def getNumber(self, query):
+ numbers = [int(s) for s in query.split() if s.isdigit()]
+ return numbers[0]
+
+ def get(self):
+ user_id = self.request.get(USER_ID_PARAM)
+ parent_key = db.Key.from_path("User", user_id)
+ contest = models.Contest.all().ancestor(parent_key).get()
+ nickname = contest.user.nickname()
+ entry = models.Entry(parent=parent_key)
+ query = self.request.get(QUERY_CGI_PARAM)
+ exercise = self.getExercise(query)
+ entry.date = datetime.datetime.now()
+ entry.reps = self.getNumber(query)
+ entry.points = exercise[2] * entry.reps
+ entry.name = exercise[0]
+ entry.put()
+
+ if user_id:
+ # Render JSONP Response
+ self.response.headers['Content-Type'] = 'applicaton/javascript'
+ self.response.out.write(ADD_FN + '(' + str(entry.points) + ',"' + entry.name + '", "' + nickname + '", "' + str(entry.key()) + '")')
+
+
+app = webapp2.WSGIApplication([
+ ('/log', LogHandler)
+], debug=True)
View
228 log_workout.html
@@ -0,0 +1,228 @@
+<html>
+<style>
+.scoreboard {
+ display: inline-block;
+ width:40%;
+ height: 40%;
+ overflow-y:auto;
+ overflow-x:hidden;
+ border: 1px solid black;
+ margin: 2px;
+ border-radius: 3px 3px 3px 1px;
+ background: rgba(242, 242, 242, 0.8);
+ position: relative;
+}
+#you {
+ border: 3px solid black;
+ box-shadow: #888 5px 5px 5px;
+}
+.entry {
+ border: 1px solid rgb(100, 100, 242);
+ padding: 6px;
+ min-height: 20px;
+}
+.exercise {
+ display: inline-block;
+ max-width: 30%;
+ font-family: sans-serif;
+}
+.points {
+ display: inline-block;
+ max-width: 30%;
+ left: 40%;
+ position: absolute;
+ font-style: italic;
+ font-weight: bold;
+}
+.score {
+ font-size: 50px;
+ position: absolute;
+ padding: 2px;
+ background: rgba(200, 242, 242, 0.9);
+ right: 0px;
+ z-index: 99;
+ bottom: 0px;
+ border-radius: 5px 0px 0px 0px;
+ cursor: default;
+}
+.name {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ background: rgba(200, 242, 242, 0.9);
+ border-radius: 0px 3px 0px 0px;
+ padding: 4px;
+ font-size:30px;
+ cursor: default;
+}
+.entry:hover {
+ opacity: 0.3;
+ cursor: pointer;
+}
+.date_separator {
+ border: 1px solid black;
+ height: 3px;
+}
+.date {
+ border: 1px solid black;
+ padding: 3px;
+}
+.delete_friend:hover {
+ background: rgb(250, 50, 50);
+}
+.default_translucent {
+ opacity: 0.6;
+}
+input {
+ margin: 10px;
+ min-width: 10%;
+ max-width: 20%;
+}
+</style>
+
+<!--Slider-->
+
+
+<input type="text" id="tf" class="cleardefault default_translucent" default_value="Enter workout" value="Enter workout"></input>
+<input type="text" id="ff" class="cleardefault default_translucent" default_value="Enter friend's e-mail" value="Enter friend's e-mail"></input>
+<div id="scorecards">
+
+{% for yourdays in users %}
+<div {% if forloop.first %}id="you"{% endif %} class="scoreboard" nickname="{{yourdays.nickname}}">
+ {% for day in yourdays %}
+ <div class="date">{{day.date}}</div>
+ <div class="day">
+ {% for exercise in day %}
+ <div class="entry" {% if forloop.parentloop.first %}entry_id="{{exercise.key}}"{% endif %}>
+ <div class="exercise">
+ {{exercise.name}}
+ </div>
+ <div class="points">
+ +{{exercise.points}}
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ <div class="date_separator"></div>
+ {% endfor %}
+ <div class="score">{{yourdays.score}}</div>
+ <div class="name {% if not forloop.first %}delete_friend{% endif %}">
+ {{yourdays.name}}
+ </div>
+</div>
+{% endfor %}
+
+</div>
+
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"> </script>
+<script>
+String.prototype.format = function() {
+ var args = arguments;
+ return this.replace(/{(\d+)}/g, function(match, number) {
+ return typeof args[number] != 'undefined'
+ ? args[number]
+ : match
+ ;
+ });
+};
+var entryHtml = '<div class="entry" entry_id="{2}"> \
+ <div class="exercise"> \
+ {0} \
+ </div> \
+ <div class="points"> \
+ +{1} \
+ </div> \
+ </div>'
+
+var score = {{score}};
+var user_id = "{{user_id}}";
+var parser = new DOMParser();
+var Ids = {
+ SCORE_CARDS : "scorecards",
+ JSONP_REQUEST : "jsonp",
+ TEXT_FIELD : "tf",
+ FRIEND_FIELD: "ff",
+ YOUR_SCORECARD: "you"
+};
+var Classes = {
+ DAYS: "day",
+ ENTRY: "entry",
+ SCORE_CARD: "scoreboard",
+ DELETE_FRIEND: "delete_friend",
+ CLEAR_DEFAULT: "cleardefault",
+ DEFAULT_TRANSLUCENT: "default_translucent"
+};
+$('#' + Ids.TEXT_FIELD).keypress(function(e) {
+ if (e.which == 13) {
+ updateBackend();
+ }
+});
+$('#' + Ids.FRIEND_FIELD).keypress(function(e) {
+ if (e.which == 13) {
+ updateFriends();
+ }
+});
+function makeJsonpRequest(url) {
+ var $script = $('<script>');
+ $script.attr('src', url);
+ $('body').append($script);
+}
+function deleteFromBackend() {
+ var entry_id = $(this).attr('entry_id');
+ makeJsonpRequest('/delete?u=' + user_id + '&e=' + entry_id);
+ var points = $(this).children('.points').html();
+ score -= parseInt(points, 10);
+ var scorecard = $('#' + Ids.YOUR_SCORECARD);
+ scorecard.find('.score').text(score);
+ $(this).remove();
+}
+function deleteFriendFromBackend() {
+ var scorecard = $(this).parents('.' + Classes.SCORE_CARD);
+ var friend_name = scorecard.attr('nickname');
+ makeJsonpRequest('/deletefriend?u=' + user_id + '&f=' + friend_name);
+ scorecard.hide('slow');
+ scorecard.remove();
+}
+function updateFriends() {
+ var text_field = $('#' + Ids.FRIEND_FIELD);
+ var url = '/addfriend?u=' + user_id + '&f=' + text_field.val();
+ text_field.val("");
+ makeJsonpRequest(url);
+}
+function updateBackend() {
+ var text_field = $('#' + Ids.TEXT_FIELD);
+ var url = '/log?u=' + user_id + '&q=' + text_field.val().replace(' ', '+');
+ text_field.val("");
+ makeJsonpRequest(url);
+}
+function addNewEntry(points, name, nickname, entry_id) {
+ var exercise = $('<div>').html(entryHtml.format(name, points, entry_id));
+ score += points;
+ var scorecard = $('[nickname="' + nickname + '"]');
+ var logbook = scorecard.find('.' + Classes.DAYS + ":first");
+ logbook.prepend(exercise);
+ exercise.find('.' + Classes.ENTRY).click(deleteFromBackend);
+ scorecard.find('.score').text(score);
+}
+function addFriend(htmlString) {
+ var scorecard = $(htmlString);
+ $('#' + Ids.SCORE_CARDS).append(scorecard);
+}
+function clearDefault() {
+ var defaultValue = $(this).attr('default_value');
+ if ($(this).val() == defaultValue) {
+ $(this).val("");
+ }
+ $(this).removeClass(Classes.DEFAULT_TRANSLUCENT);
+ $(this).focusout(makeDefault);
+}
+function makeDefault() {
+ var defaultValue = $(this).attr('default_value');
+ $(this).val(defaultValue);
+ $(this).addClass(Classes.DEFAULT_TRANSLUCENT);
+}
+$('#' + Ids.YOUR_SCORECARD).find('.' + Classes.ENTRY).click(deleteFromBackend);
+$('.' + Classes.DELETE_FRIEND).click(deleteFriendFromBackend);
+$('.' + Classes.CLEAR_DEFAULT).focus(clearDefault);
+</script>
+</html>
View
0  main.app
No changes.
View
60 main.py
@@ -0,0 +1,60 @@
+#!/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.
+#
+import webapp2
+
+import os
+import datetime
+import models
+import common
+from google.appengine.ext import db
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+class MainHandler(webapp2.RequestHandler):
+ def get(self):
+ current_user = users.get_current_user()
+ if not current_user:
+ self.redirect(users.create_login_url(self.request.uri))
+ return
+ contest = models.Contest.all().filter('user =', current_user).get()
+ if not contest:
+ contest = models.Contest(parent=db.Key.from_path("User", current_user.user_id()),user=current_user)
+ contest.put()
+ competitors = common.getCompetitors(current_user)
+ everyone = [common.getDays(competitor) for competitor in competitors]
+ user_entries = common.getDays(current_user)
+ today = common.Record()
+ today.date = datetime.datetime.now().date()
+ if len(user_entries) == 0 or user_entries[0].date != today.date:
+ user_entries.insert(0, today)
+
+ everyone.insert(0, user_entries)
+ # Fetch records for others
+ # Fetch my record
+ template_values = {
+ 'users' : everyone,
+ 'score' : user_entries.score,
+ 'user_id' : current_user.user_id(),
+ }
+ path = os.path.join(os.path.dirname(__file__), 'log_workout.html')
+ self.response.out.write(template.render(path, template_values))
+
+
+app = webapp2.WSGIApplication([
+ ('/', MainHandler)
+], debug=True)
View
21 models.py
@@ -0,0 +1,21 @@
+from google.appengine.ext import db
+from google.appengine.api import users
+
+exercises = { 'pushups' : ('pushups', 'reps', 10),
+ 'pullups' : ('pullups', 'reps', 10),
+ 'burpees' : ('burpees', 'reps', 20),
+ 'squats' : ('squats', 'reps', 10),
+ 'punching' : ('punching', 'minutes', 60),
+ 'jumping' : ('jumping', 'minutes', 40),
+ 'plank' : ('plank', 'minutes', 60) }
+
+class Entry(db.Model):
+ reps = db.IntegerProperty()
+ points = db.IntegerProperty()
+ date = db.DateTimeProperty()
+ name = db.StringProperty(choices=set(exercises.keys()))
+
+class Contest(db.Model):
+ participants = db.ListProperty(users.User)
+ user = db.UserProperty()
+
View
31 newcontest.py
@@ -0,0 +1,31 @@
+import os
+import cgi
+import datetime
+import re
+import models
+import webapp2
+
+from google.appengine.ext import db
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+REPS_CGI_PARAM = "r"
+
+class MainHandler(webapp2.RequestHandler):
+ def get(self):
+ entry = models.Entry
+ # entry.time = get the current time
+ entry.reps = self.request.get(REPS_CGI_PARAM)
+ entry.user = users.get_current_user()
+ entry.points = exercise.points_per_unit * entry.reps
+
+ if entry.user:
+ # Render JSONP Response
+ self.response.headers['Content-Type'] = 'applicaton/javascript'
+ self.response.out.write(ADD_FN + '(' + entry.points + ',' + entry.exercise.name)
+
+
+app = webapp2.WSGIApplication([
+ ('/', MainHandler)
+], debug=True)
View
22 scorecard.html
@@ -0,0 +1,22 @@
+<div class="scoreboard" nickname="{{yourdays.nickname}}"> \
+ {% for day in yourdays %} \
+ <div class="date">{{day.date}}</div> \
+ <div class="day"> \
+ {% for exercise in day %} \
+ <div class="entry"> \
+ <div class="exercise"> \
+ {{exercise.name}} \
+ </div> \
+ <div class="points"> \
+ +{{exercise.points}} \
+ </div> \
+ </div> \
+ {% endfor %} \
+ </div> \
+ <div class="date_separator"></div> \
+ {% endfor %} \
+ <div class="score">{{yourdays.score}}</div> \
+ <div class="name delete_friend"> \
+ {{yourdays.name}} \
+ </div> \
+</div>

No commit comments for this range

Something went wrong with that request. Please try again.