jenkins-bot has submitted this change and it was merged. Change subject: Let users star and unstar queries ......................................................................
Let users star and unstar queries - Displays starred queries info in User profile page - Adds new star table Change-Id: If5e976522969e7d6d43569f108c212b76c43eff0 --- M quarry/web/app.py A quarry/web/models/star.py M quarry/web/static/css/query/view.css M quarry/web/static/css/user.css M quarry/web/static/js/query/view.js M quarry/web/templates/query/view.html M quarry/web/templates/user.html M tables.sql 8 files changed, 164 insertions(+), 12 deletions(-) Approvals: Yuvipanda: Looks good to me, approved jenkins-bot: Verified diff --git a/quarry/web/app.py b/quarry/web/app.py index 64a371e..c57b71c 100644 --- a/quarry/web/app.py +++ b/quarry/web/app.py @@ -4,12 +4,13 @@ from models.query import Query from models.queryrevision import QueryRevision from models.queryrun import QueryRun +from models.star import Star import json import yaml import time import os from sqlalchemy import desc, func -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import sessionmaker, joinedload from redissession import RedisSessionInterface from mwoauth import ConsumerToken, Handshaker from connections import Connections @@ -99,19 +100,67 @@ user_name = user_name.replace('_', ' ').lower() user = g.session.query(User).filter(func.lower(User.username) == user_name).one() stats = { - 'query_count': g.session.query(func.count(Query.id)).filter(Query.user_id == user.id).scalar() + 'query_count': g.session.query(func.count(Query.id)).filter(Query.user_id == user.id).scalar(), + 'stars_count': g.session.query(func.count(Star.id)).filter(Star.user_id == user.id).scalar() } recent_queries = g.session.query(Query)\ .filter(Query.user_id == user.id)\ .order_by(desc(Query.last_touched))\ + .limit(10) + self_stars = g.session.query(Star).join(Star.query)\ + .options(joinedload(Star.query))\ + .filter(Star.user_id == user.id)\ + .filter(Query.user_id == user.id)\ + .order_by(desc(Star.timestamp))\ + .limit(10) + other_stars = g.session.query(Star).join(Star.query) \ + .options(joinedload(Star.query))\ + .filter(Star.user_id == user.id) \ + .filter(Query.user_id != user.id) \ + .order_by(desc(Star.timestamp))\ .limit(10) return render_template( "user.html", display_user=user, user=g.user, stats=stats, - recent_queries=recent_queries + recent_queries=recent_queries, + self_stars=self_stars, + other_stars=other_stars ) + + +@app.route("/api/query/unstar", methods=["POST"]) +def unstar_query(): + if g.user is None: + return "Unauthorized access", 403 + query = g.session.query(Query).get(request.form['query_id']) + if query: + star = g.session.query(Star)\ + .filter(Star.query_id == request.form['query_id'])\ + .filter(Star.user_id == g.user.id)\ + .one() + g.session.delete(star) + g.session.commit() + return "" + else: + return "Query not found", 404 + + +@app.route("/api/query/star", methods=["POST"]) +def star_query(): + if g.user is None: + return "Unauthorized access", 403 + query = g.session.query(Query).get(request.form['query_id']) + if query: + star = Star() + star.user = g.user + star.query = query + g.session.add(star) + g.session.commit() + return "" + else: + return "Query not found", 404 @app.route("/query/new") @@ -136,9 +185,15 @@ def query_show(query_id): query = g.session.query(Query).filter(Query.id == query_id).one() can_edit = g.user is not None and g.user.id == query.user_id + is_starred = False + if g.user: + is_starred = g.session.query(func.count(Star.id))\ + .filter(Star.user_id == g.user.id)\ + .filter(Star.query_id == query_id).scalar() == 1 jsvars = { 'query_id': query.id, - 'can_edit': can_edit + 'can_edit': can_edit, + 'is_starred': is_starred } if query.latest_rev and query.latest_rev.latest_run: diff --git a/quarry/web/models/star.py b/quarry/web/models/star.py new file mode 100644 index 0000000..ff93654 --- /dev/null +++ b/quarry/web/models/star.py @@ -0,0 +1,15 @@ +from sqlalchemy import Column, Integer, ForeignKey, DateTime +from sqlalchemy.orm import relationship +from base import Base + + +class Star(Base): + __tablename__ = 'star' + + id = Column(Integer, primary_key=True) + user_id = Column(Integer, ForeignKey('user.id')) + timestamp = Column(DateTime) + query_id = Column(Integer, ForeignKey('query.id')) + + query = relationship('Query', uselist=False) + user = relationship('User', uselist=False) diff --git a/quarry/web/static/css/query/view.css b/quarry/web/static/css/query/view.css index 0f6c648..4ef0d85 100644 --- a/quarry/web/static/css/query/view.css +++ b/quarry/web/static/css/query/view.css @@ -2,6 +2,23 @@ margin-top: 20px; } +.starred .only-starred { + display: block; +} + +.starred .only-non-starred { + display: none; +} + +.only-starred { + display: none; +} + +#title-actions-container button { + margin-top: 18px; + float: right; +} + .CodeMirror { font-family: Monaco, Consolas, "Ubuntu Mono", monospace; height: auto; diff --git a/quarry/web/static/css/user.css b/quarry/web/static/css/user.css index 3bba155..65f1688 100644 --- a/quarry/web/static/css/user.css +++ b/quarry/web/static/css/user.css @@ -8,15 +8,15 @@ padding-bottom: 12px; } -#query-items-list { +.query-items-list { list-style: none; padding-left: 0; } -#query-items-list li { +.query-items-list li { padding: 4px 0px; } -#query-items-list li a.query-title { +.query-items-list li a.query-title { font-size: 1.2em; } diff --git a/quarry/web/static/js/query/view.js b/quarry/web/static/js/query/view.js index 0de44d1..7223f99 100644 --- a/quarry/web/static/js/query/view.js +++ b/quarry/web/static/js/query/view.js @@ -20,6 +20,22 @@ } ); } + $("#un-star-query").click( function() { + $.post( "/api/query/unstar", { + query_id: vars.query_id + }).done(function( data ) { + $('#content').removeClass('starred'); + }); + }); + + $("#star-query").click( function() { + $.post( "/api/query/star", { + query_id: vars.query_id + }).done(function( data ) { + $('#content').addClass('starred'); + }); + }); + $('#run-code').click( function() { $.post( "/api/query/run", { text: editor.getValue(), diff --git a/quarry/web/templates/query/view.html b/quarry/web/templates/query/view.html index b902d29..4331500 100644 --- a/quarry/web/templates/query/view.html +++ b/quarry/web/templates/query/view.html @@ -12,11 +12,23 @@ <script src="/static/js/query/view.js"> </script> {% endblock %} {% block content %} -<div id="content" class="container {% if jsvars.can_edit %}edit{% else %}no-edit{% endif %}"> +<div id="content" class="container {% if jsvars.can_edit %}edit{% else %}no-edit{% endif %} {% if jsvars.is_starred %}starred{% endif %}"> <div class="row" id="title-container"> - <h2 id='title'>{{query.title}}</h2> + <div class="col-md-10"> + <h2 id='title'>{{query.title}}</h2> + </div> + <div class="col-md-2" id="title-actions-container"> + {% if user %} + <button id="un-star-query" type="button" class="btn btn-info btn-sm only-starred"> + <span class="glyphicon glyphicon-star"></span> Unstar + </button> + <button id="star-query" type="button" class="btn btn-info btn-sm only-non-starred"> + <span class="glyphicon glyphicon-star-empty"></span> Star + </button> + {% endif %} + </div> </div> - <div class="row"> + <div> <h3>SQL</h3> <textarea id="code">{% if latest_rev %}{{ latest_rev.text }}{%endif%}</textarea> </div> diff --git a/quarry/web/templates/user.html b/quarry/web/templates/user.html index 3fc7b58..c66848d 100644 --- a/quarry/web/templates/user.html +++ b/quarry/web/templates/user.html @@ -17,14 +17,42 @@ </div> </div> </div> - <div class="query-list-container"> + <div class="row"> + <div class="col-md-6 query-list-container"> + <h3>Self starred Queries</h3> + <ul class="query-items-list"> + {% for star in self_stars %} + <li class="query-item"> + <a class="query-title" href="/query/{{star.query.id}}">{{star.query.title}}</a> + </li> + {% else %} + This user has not starred any of his queries yet. + {% endfor %} + </ul> + </div> + <div class="col-md-6 query-list-container"> + <h3>Other starred Queries</h3> + <ul class="query-items-list"> + {% for star in other_stars %} + <li class="query-item"> + <a class="query-title" href="/query/{{star.query.id}}">{{star.query.title}}</a> + </li> + {% else %} + This user has not starred any other user's queries yet. + {% endfor %} + </ul> + </div> + </div> + <div> <h3>Recent Queries</h3> - <ul id="query-items-list"> + <ul class="query-items-list"> {% for query in recent_queries %} <li class="query-item"> <a class="query-title" href="/query/{{query.id}}">{{query.title}}</a> <small>{{query.last_touched|timesince}}</small> </li> + {% else %} + This user has not run any queries yet {% endfor %} </ul> </div> diff --git a/tables.sql b/tables.sql index cccc846..e796094 100644 --- a/tables.sql +++ b/tables.sql @@ -35,3 +35,12 @@ task_id VARCHAR(36) BINARY ); CREATE INDEX query_run_status_index ON query_run(status); + +CREATE TABLE star( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + user_id INT UNSIGNED NOT NULL, + query_id INT UNSIGNED NOT NULL, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX star_user_id_index ON star(user_id); +CREATE INDEX star_query_id_index ON star(query_id); -- To view, visit https://gerrit.wikimedia.org/r/153963 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: If5e976522969e7d6d43569f108c212b76c43eff0 Gerrit-PatchSet: 4 Gerrit-Project: analytics/quarry/web Gerrit-Branch: master Gerrit-Owner: Yuvipanda <yuvipa...@gmail.com> Gerrit-Reviewer: Springle <sprin...@wikimedia.org> Gerrit-Reviewer: Yuvipanda <yuvipa...@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits