--
cgit v1.2.3
From a9f63aadeeedb7c28bbcd16396c8c6e7d5cbbfd0 Mon Sep 17 00:00:00 2001
From: Sam
Date: Tue, 31 Dec 2013 08:52:23 +0000
Subject: Finished code to remove a trait or multiple traits from a collection
Wrote code to make buttons a little cleaner and more obvious when dealing with collections (they now enable themselves when traits that can be added or removed to/from a collection are selected)
---
wqflask/wqflask/collect.py | 58 ++++++++++++++---
wqflask/wqflask/model.py | 6 ++
.../static/new/javascript/search_results.coffee | 61 +++++++++++++++++
.../static/new/javascript/search_results.js | 76 +++++++++++++++++++++-
wqflask/wqflask/templates/collections/add.html | 2 +-
wqflask/wqflask/templates/collections/view.html | 12 +++-
6 files changed, 203 insertions(+), 12 deletions(-)
diff --git a/wqflask/wqflask/collect.py b/wqflask/wqflask/collect.py
index 2bf5b602..29b73130 100644
--- a/wqflask/wqflask/collect.py
+++ b/wqflask/wqflask/collect.py
@@ -67,8 +67,8 @@ def collections_new():
return create_new(collection_name)
elif "add_to_existing" in params:
return add_traits(params, collection_name)
- elif "default" in params:
- return add_traits(params, "default")
+ elif "Default" in params:
+ return add_traits(params, "Default")
else:
CauseAnError
@@ -78,14 +78,14 @@ def collections_new():
def add_traits(params, collection_name):
print("---> params are:", params.keys())
print(" type(params):", type(params))
- if collection_name=="default":
- uc = g.user_session.user_ob.get_collection_by_name("default")
+ if collection_name=="Default":
+ uc = g.user_session.user_ob.get_collection_by_name("Default")
# Doesn't exist so we'll create it
if not uc:
- return create_new("default")
+ return create_new("Default")
else:
uc = model.UserCollection.query.get(params['existing_collection'])
- members = set(json.loads(uc.members))
+ members = uc.members_as_set() #set(json.loads(uc.members))
len_before = len(members)
traits = process_traits(params['traits'])
@@ -111,7 +111,8 @@ def add_traits(params, collection_name):
def process_traits(unprocessed_traits):
print("unprocessed_traits are:", unprocessed_traits)
- unprocessed_traits = unprocessed_traits.split(",")
+ if isinstance(unprocessed_traits, basestring):
+ unprocessed_traits = unprocessed_traits.split(",")
traits = set()
for trait in unprocessed_traits:
data, _separator, hmac = trait.rpartition(':')
@@ -144,13 +145,54 @@ def create_new(collection_name):
@app.route("/collections/list")
def list_collections():
params = request.args
- user_collections = g.user_session.user_ob.user_collections
+ user_collections = list(g.user_session.user_ob.user_collections)
+ print("user_collections are:", user_collections)
return render_template("collections/list.html",
params = params,
user_collections = user_collections,
)
+@app.route("/collections/remove", methods=('POST',))
+def remove_traits():
+ params = request.form
+ print("params are:", params)
+ uc_id = params['uc_id']
+ uc = model.UserCollection.query.get(uc_id)
+ traits_to_remove = params.getlist('traits[]')
+ print("traits_to_remove are:", traits_to_remove)
+ traits_to_remove = process_traits(traits_to_remove)
+ print("\n\n after processing, traits_to_remove:", traits_to_remove)
+ all_traits = uc.members_as_set()
+ print(" all_traits:", all_traits)
+ members_now = all_traits - traits_to_remove
+ print(" members_now:", members_now)
+ print("Went from {} to {} members in set.".format(len(all_traits), len(members_now)))
+ uc.members = json.dumps(list(members_now))
+ uc.changed_timestamp = datetime.datetime.utcnow()
+ db_session.commit()
+
+ # We need to return something so we'll return this...maybe in the future
+ # we can use it to check the results
+ return str(len(members_now))
+
+
+
+@app.route("/collections/delete", methods=('POST',))
+def delete_collection():
+ params = request.form
+ uc_id = params['uc_id']
+ uc = model.UserCollection.query.get(uc_id)
+ # Todo: For now having the id is good enough since it's so unique
+ # But might want to check ownership in the future
+ collection_name = uc.name
+ db_session.delete(uc)
+ db_session.commit()
+ flash("We've deletet the collection: {}.".format(collection_name), "alert-info")
+
+ return redirect(url_for('list_collections'))
+
+
@app.route("/collections/view")
def view_collection():
params = request.args
diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py
index 192aedd0..e588e78a 100644
--- a/wqflask/wqflask/model.py
+++ b/wqflask/wqflask/model.py
@@ -10,6 +10,8 @@ from flask.ext.sqlalchemy import SQLAlchemy
from wqflask import app
+import sqlalchemy
+
from sqlalchemy import (Column, Integer, String, Table, ForeignKey, Unicode, Boolean, DateTime,
Text, Index)
from sqlalchemy.orm import relationship, backref
@@ -153,3 +155,7 @@ class UserCollection(Base):
def num_members(self):
print("members are:", json.loads(self.members))
return len(json.loads(self.members))
+
+
+ def members_as_set(self):
+ return set(json.loads(self.members))
diff --git a/wqflask/wqflask/static/new/javascript/search_results.coffee b/wqflask/wqflask/static/new/javascript/search_results.coffee
index 34989a77..84cf7f0a 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.coffee
+++ b/wqflask/wqflask/static/new/javascript/search_results.coffee
@@ -1,4 +1,8 @@
$ ->
+ # These are also used by collections view
+ # So the name search_results in the filename is misleading
+
+ checked_traits = null
select_all = ->
console.log("selected_all")
@@ -17,6 +21,59 @@ $ ->
console.log("checked is:", traits)
$.colorbox({href:"/collections/add?traits=#{traits}"})
+ removed_traits = ->
+ # After we've removed the traits from the database we get rid of them in the table
+ console.log('in removed_traits with checked_traits:', checked_traits)
+ checked_traits.closest("tr").fadeOut()
+
+
+ change_buttons = ->
+ buttons = ["#add", "#remove"]
+ num_checked = $('.trait_checkbox:checked').length
+ console.log("num_checked is:", num_checked)
+ if (num_checked == 0)
+ for button in buttons
+ $(button).prop("disabled", true)
+ else
+ for button in buttons
+ $(button).prop("disabled", false)
+
+
+ if (num_checked > 1)
+ console.log("in loop")
+ for item in buttons
+ console.log(" processing item:", item)
+ text = $(item).html()
+ if text.indexOf("Records") == -1
+ text = text.replace("Record", "Records")
+ $(item).html(text)
+ else
+ console.log("in loop")
+ for item in buttons
+ console.log(" processing item:", item)
+ text = $(item).html()
+ text = text.replace("Records", "Record")
+ $(item).html(text)
+
+
+ # remove is only used by collections view
+ remove = ->
+ checked_traits = $("#trait_table input:checked")
+ traits = checked_traits.map(->
+ return $(this).val()).get()
+ console.log("checked length is:", traits.length)
+ console.log("checked is:", traits)
+ uc_id = $("#uc_id").val()
+ console.log("uc.id is:", uc_id)
+ # Todo: Consider adding a failure message
+ $.ajax(
+ type: "POST"
+ url: "/collections/remove"
+ data:
+ uc_id: uc_id
+ traits: traits
+ success: removed_traits
+ )
@@ -24,3 +81,7 @@ $ ->
$("#deselect_all").click(deselect_all)
$("#invert").click(invert)
$("#add").click(add)
+ $("#remove").click(remove)
+
+ $('.trait_checkbox').click(change_buttons)
+ $('.btn').click(change_buttons)
diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js
index 3efaca8b..477c9b94 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.js
+++ b/wqflask/wqflask/static/new/javascript/search_results.js
@@ -2,7 +2,8 @@
(function() {
$(function() {
- var add, deselect_all, invert, select_all;
+ var add, change_buttons, checked_traits, deselect_all, invert, remove, removed_traits, select_all;
+ checked_traits = null;
select_all = function() {
console.log("selected_all");
return $(".trait_checkbox").prop('checked', true);
@@ -24,10 +25,81 @@
href: "/collections/add?traits=" + traits
});
};
+ removed_traits = function() {
+ console.log('in removed_traits with checked_traits:', checked_traits);
+ return checked_traits.closest("tr").fadeOut();
+ };
+ change_buttons = function() {
+ var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len1, _len2, _len3, _results, _results1;
+ buttons = ["#add", "#remove"];
+ num_checked = $('.trait_checkbox:checked').length;
+ console.log("num_checked is:", num_checked);
+ if (num_checked === 0) {
+ for (_i = 0, _len = buttons.length; _i < _len; _i++) {
+ button = buttons[_i];
+ $(button).prop("disabled", true);
+ }
+ } else {
+ for (_j = 0, _len1 = buttons.length; _j < _len1; _j++) {
+ button = buttons[_j];
+ $(button).prop("disabled", false);
+ }
+ }
+ if (num_checked > 1) {
+ console.log("in loop");
+ _results = [];
+ for (_k = 0, _len2 = buttons.length; _k < _len2; _k++) {
+ item = buttons[_k];
+ console.log(" processing item:", item);
+ text = $(item).html();
+ if (text.indexOf("Records") === -1) {
+ text = text.replace("Record", "Records");
+ _results.push($(item).html(text));
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ } else {
+ console.log("in loop");
+ _results1 = [];
+ for (_l = 0, _len3 = buttons.length; _l < _len3; _l++) {
+ item = buttons[_l];
+ console.log(" processing item:", item);
+ text = $(item).html();
+ text = text.replace("Records", "Record");
+ _results1.push($(item).html(text));
+ }
+ return _results1;
+ }
+ };
+ remove = function() {
+ var traits, uc_id;
+ checked_traits = $("#trait_table input:checked");
+ traits = checked_traits.map(function() {
+ return $(this).val();
+ }).get();
+ console.log("checked length is:", traits.length);
+ console.log("checked is:", traits);
+ uc_id = $("#uc_id").val();
+ console.log("uc.id is:", uc_id);
+ return $.ajax({
+ type: "POST",
+ url: "/collections/remove",
+ data: {
+ uc_id: uc_id,
+ traits: traits
+ },
+ success: removed_traits
+ });
+ };
$("#select_all").click(select_all);
$("#deselect_all").click(deselect_all);
$("#invert").click(invert);
- return $("#add").click(add);
+ $("#add").click(add);
+ $("#remove").click(remove);
+ $('.trait_checkbox').click(change_buttons);
+ return $('.btn').click(change_buttons);
});
}).call(this);
diff --git a/wqflask/wqflask/templates/collections/add.html b/wqflask/wqflask/templates/collections/add.html
index c87203b1..faee4f78 100644
--- a/wqflask/wqflask/templates/collections/add.html
+++ b/wqflask/wqflask/templates/collections/add.html
@@ -10,7 +10,7 @@
Choose this if you're in a hurry or don't plan on using the collection again.
If you are unsure this is probably the option you want.
-
+
diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html
index 79eeac26..7f588e84 100644
--- a/wqflask/wqflask/templates/collections/view.html
+++ b/wqflask/wqflask/templates/collections/view.html
@@ -9,8 +9,17 @@
+
+
@@ -58,7 +67,8 @@
-
+
+
--
cgit v1.2.3
From c4f507c6e1042a1e42f0fe8c08e2eff13fa12d8c Mon Sep 17 00:00:00 2001
From: Sam
Date: Thu, 30 Jan 2014 04:35:21 +0000
Subject: Before trying to fix user login issue
---
wqflask/wqflask/collect.py | 19 +++++++++++++------
wqflask/wqflask/model.py | 30 ++++++++++++++++++++++++++++++
wqflask/wqflask/templates/base.html | 8 ++++++++
3 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/wqflask/wqflask/collect.py b/wqflask/wqflask/collect.py
index 29b73130..b1ea46d8 100644
--- a/wqflask/wqflask/collect.py
+++ b/wqflask/wqflask/collect.py
@@ -48,12 +48,19 @@ from base import trait
@app.route("/collections/add")
def collections_add():
- user_collections = g.user_session.user_ob.user_collections
- print("user_collections are:", user_collections)
- return render_template("collections/add.html",
- traits=request.args['traits'],
- user_collections = user_collections,
- )
+ traits=request.args['traits'],
+
+ if g.user_session.logged_in:
+ user_collections = g.user_session.user_ob.user_collections
+ print("user_collections are:", user_collections)
+ return render_template("collections/add.html",
+ traits=traits,
+ user_collections = user_collections,
+ )
+ else:
+ return render_template("collections/add_anonymous.html",
+ traits=traits
+ )
@app.route("/collections/new")
diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py
index e588e78a..71bda550 100644
--- a/wqflask/wqflask/model.py
+++ b/wqflask/wqflask/model.py
@@ -62,6 +62,25 @@ class User(Base):
lazy='dynamic',
)
+ def display_num_collections(self):
+ """
+ Returns the number of collections or a blank string if there are zero.
+
+
+ Because this is so unimportant...we wrap the whole thing in a try/expect...last thing we
+ want is a webpage not to be displayed because of an error here
+
+ Importand TODO: use redis to cache this, don't want to be constantly computing it
+
+ """
+ try:
+ num = len(list(self.user_collections))
+ return display_collapsible(num)
+ except Exception as why:
+ print("Couldn't display_num_collections:", why)
+ return ""
+
+
def get_collection_by_name(self, collection_name):
try:
collect = self.user_collections.filter_by(name=collection_name).one()
@@ -156,6 +175,17 @@ class UserCollection(Base):
print("members are:", json.loads(self.members))
return len(json.loads(self.members))
+ #@property
+ #def display_num_members(self):
+ # return display_collapsible(self.num_members)
+
def members_as_set(self):
return set(json.loads(self.members))
+
+
+def display_collapsible(number):
+ if number:
+ return number
+ else:
+ return ""
diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html
index 9b98c955..48078670 100644
--- a/wqflask/wqflask/templates/base.html
+++ b/wqflask/wqflask/templates/base.html
@@ -103,6 +103,14 @@
Links
+
+ Collections
+ {% if g.user_session.user_ob %}
+ {{ g.user_session.user_ob.display_num_collections() }}
+ {% endif %}
+
+
+
{% if g.user_session.logged_in %}
Sign out
--
cgit v1.2.3
From 1270a617ce10302c188f9f989d34eaf477ee6521 Mon Sep 17 00:00:00 2001
From: Sam
Date: Thu, 30 Jan 2014 05:11:24 +0000
Subject: Added forgotten html page to repo
Fixed bugs where-
- User tried to login with an email address that hasn't been registered
- User tries to register an email address that was already registered
Testing is still needed to confirm bugs were fixed properly and new ones weren't introduced
---
wqflask/wqflask/user_manager.py | 74 +++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 29 deletions(-)
diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py
index 1d0d9846..ff4535bb 100644
--- a/wqflask/wqflask/user_manager.py
+++ b/wqflask/wqflask/user_manager.py
@@ -22,6 +22,7 @@ import urlparse
import simplejson as json
+import sqlalchemy
from sqlalchemy import orm
#from redis import StrictRedis
@@ -188,7 +189,15 @@ class RegisterUser(object):
self.new_user = model.User(**self.user.__dict__)
db_session.add(self.new_user)
- db_session.commit()
+
+ try:
+ db_session.commit()
+ except sqlalchemy.exc.IntegrityError:
+ # This exception is thrown if the email address is already in the database
+ # To do: Perhaps put a link to sign in using an existing account here
+ self.errors.append("An account with this email address already exists. "
+ "Click the button above to sign in using an existing account.")
+ return
print("Adding verification email to queue")
#self.send_email_verification()
@@ -372,37 +381,44 @@ class LoginUser(object):
if not params:
return render_template("new_security/login_user.html")
else:
- user = model.User.query.filter_by(email_address=params['email_address']).one()
- submitted_password = params['password']
- pwfields = Struct(json.loads(user.password))
- encrypted = Password(submitted_password,
- pwfields.salt,
- pwfields.iterations,
- pwfields.keylength,
- pwfields.hashfunc)
- print("\n\nComparing:\n{}\n{}\n".format(encrypted.password, pwfields.password))
- valid = pbkdf2.safe_str_cmp(encrypted.password, pwfields.password)
- print("valid is:", valid)
-
- if valid and not user.confirmed:
- VerificationEmail(user)
- return render_template("new_security/verification_still_needed.html",
- subject=VerificationEmail.subject)
-
-
- if valid:
- if params.get('remember'):
- print("I will remember you")
- self.remember_me = True
-
- return self.actual_login(user)
-
+ try:
+ user = model.User.query.filter_by(email_address=params['email_address']).one()
+ except sqlalchemy.orm.exc.NoResultFound:
+ print("No account exists for that email address")
+ valid = False
+ user = None
else:
+ submitted_password = params['password']
+ pwfields = Struct(json.loads(user.password))
+ encrypted = Password(submitted_password,
+ pwfields.salt,
+ pwfields.iterations,
+ pwfields.keylength,
+ pwfields.hashfunc)
+ print("\n\nComparing:\n{}\n{}\n".format(encrypted.password, pwfields.password))
+ valid = pbkdf2.safe_str_cmp(encrypted.password, pwfields.password)
+ print("valid is:", valid)
+
+ if valid and not user.confirmed:
+ VerificationEmail(user)
+ return render_template("new_security/verification_still_needed.html",
+ subject=VerificationEmail.subject)
+
+
+ if valid:
+ if params.get('remember'):
+ print("I will remember you")
+ self.remember_me = True
+
+ return self.actual_login(user)
+
+ else:
+ if user:
self.unsuccessful_login(user)
- flash("Invalid email-address or password. Please try again.", "alert-error")
- response = make_response(redirect(url_for('login')))
+ flash("Invalid email-address or password. Please try again.", "alert-error")
+ response = make_response(redirect(url_for('login')))
- return response
+ return response
def actual_login(self, user, assumed_by=None):
"""The meat of the logging in process"""
--
cgit v1.2.3
From 1ab9e95d11da24e087774ac38786ae934f783fa6 Mon Sep 17 00:00:00 2001
From: Sam
Date: Tue, 25 Feb 2014 21:30:51 +0000
Subject: Added untracked file
---
.../templates/collections/add_anonymous.html | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 wqflask/wqflask/templates/collections/add_anonymous.html
diff --git a/wqflask/wqflask/templates/collections/add_anonymous.html b/wqflask/wqflask/templates/collections/add_anonymous.html
new file mode 100644
index 00000000..9259f667
--- /dev/null
+++ b/wqflask/wqflask/templates/collections/add_anonymous.html
@@ -0,0 +1,22 @@
+
+
+
--
cgit v1.2.3