From 2e689898634f1722a65ec642d14d0c8021f6f67a Mon Sep 17 00:00:00 2001 From: Mortonian Date: Thu, 26 Feb 2015 09:54:48 -0500 Subject: [PATCH 01/14] Specific queryset rather than infer from model. Because inferring from model didn't work. Possible version conflict? --- djangular/polls/views.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/djangular/polls/views.py b/djangular/polls/views.py index 9680098..bb31838 100644 --- a/djangular/polls/views.py +++ b/djangular/polls/views.py @@ -5,14 +5,16 @@ class QuestionList(generics.ListCreateAPIView): - model = Question + queryset = Question.objects.all() + #model = Question serializer_class = QuestionSerializer permission_classes = [ permissions.AllowAny ] class QuestionDetail(generics.RetrieveAPIView): - model = Question + queryset = Question.objects.all() + #model = Question serializer_class = QuestionSerializer lookup_url_kwarg = 'question_pk' permission_classes = [ @@ -20,7 +22,8 @@ class QuestionDetail(generics.RetrieveAPIView): ] class ChoiceUpdate(generics.UpdateAPIView): - model = Choice + queryset = Choice.objects.all() + #model = Choice serializer_class = ChoiceSerializer lookup_url_kwarg = 'choice_pk' permission_classes = [ @@ -28,7 +31,8 @@ class ChoiceUpdate(generics.UpdateAPIView): ] class ChoiceList(generics.ListCreateAPIView): - model = Choice + queryset = Choice.objects.all() + #model = Choice serializer_class = ChoiceSerializer permission_classes = [ permissions.AllowAny From 22a55aa54e85a84e128c64734269208c906a4125 Mon Sep 17 00:00:00 2001 From: Mortonian Date: Thu, 26 Feb 2015 12:49:05 -0500 Subject: [PATCH 02/14] Separate results into its own route/view. Remove now unnec. 'vote' from questionDetails controller --- djangular/frontend/app.coffee | 10 +++++++++ djangular/frontend/controllers.coffee | 6 +++-- djangular/static/js/app.js | 12 ++++++++++ djangular/static/js/controllers.js | 9 ++++++-- djangular/templates/polls/index.html | 32 ++++++++++++++++++--------- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/djangular/frontend/app.coffee b/djangular/frontend/app.coffee index 9d29d2c..d2c6712 100644 --- a/djangular/frontend/app.coffee +++ b/djangular/frontend/app.coffee @@ -28,6 +28,16 @@ app.config(($interpolateProvider, $stateProvider, $urlRouterProvider) -> question.get($stateParams.questionId) return question ) + .state('questionResults' + url: '/{questionId:[0-9]+}/results' + templateUrl: 'questionResults' + controller: 'questionResultsController' + resolve: + question : ($stateParams, $log, Question)-> + question = new Question(null) + question.get($stateParams.questionId) + return question + ) ) diff --git a/djangular/frontend/controllers.coffee b/djangular/frontend/controllers.coffee index c60a5e6..da74522 100644 --- a/djangular/frontend/controllers.coffee +++ b/djangular/frontend/controllers.coffee @@ -6,7 +6,6 @@ controllers.controller('questionListController', ($scope, $state, $log, question controllers.controller('questionDetailController', ($scope, $state, $log, question) -> $scope.question = question - $scope.voted = false $scope.voteChoice = 0 $scope.vote = -> @@ -16,7 +15,10 @@ controllers.controller('questionDetailController', ($scope, $state, $log, questi $scope.question.totalVotes+=1 choice.update() break - $scope.voted = true + $state.go('questionResults', {questionId:question.id}) ) +controllers.controller('questionResultsController', ($scope, $state, $log, question) -> + $scope.question = question +) diff --git a/djangular/static/js/app.js b/djangular/static/js/app.js index a2bd0c0..2507a93 100644 --- a/djangular/static/js/app.js +++ b/djangular/static/js/app.js @@ -29,6 +29,18 @@ return question; } } + }).state('questionResults', { + url: '/{questionId:[0-9]+}/results', + templateUrl: 'questionResults', + controller: 'questionResultsController', + resolve: { + question: function($stateParams, $log, Question) { + var question; + question = new Question(null); + question.get($stateParams.questionId); + return question; + } + } }); }); diff --git a/djangular/static/js/controllers.js b/djangular/static/js/controllers.js index dcb935c..e18df6c 100644 --- a/djangular/static/js/controllers.js +++ b/djangular/static/js/controllers.js @@ -9,7 +9,6 @@ controllers.controller('questionDetailController', function($scope, $state, $log, question) { $scope.question = question; - $scope.voted = false; $scope.voteChoice = 0; return $scope.vote = function() { var choice, _i, _len, _ref; @@ -23,8 +22,14 @@ break; } } - return $scope.voted = true; + return $state.go('questionResults', { + questionId: question.id + }); }; }); + controllers.controller('questionResultsController', function($scope, $state, $log, question) { + return $scope.question = question; + }); + }).call(this); diff --git a/djangular/templates/polls/index.html b/djangular/templates/polls/index.html index 144f33b..86bceac 100644 --- a/djangular/templates/polls/index.html +++ b/djangular/templates/polls/index.html @@ -15,6 +15,12 @@ [[question.question_text]] + -- + + + ([[question.totalVotes]] responses) + + @@ -22,7 +28,7 @@ + + + + {% endblock %} {% block javascript %} From 32631816cbd69cf92f5af0f2d975a3204229ed71 Mon Sep 17 00:00:00 2001 From: Mortonian Date: Thu, 26 Feb 2015 12:54:24 -0500 Subject: [PATCH 03/14] stop tracking grunt-generated javascript --- .gitignore | 4 + djangular/static/js/app.js | 63 --------------- djangular/static/js/controllers.js | 35 --------- djangular/static/js/directives.js | 34 --------- djangular/static/js/services.js | 118 ----------------------------- 5 files changed, 4 insertions(+), 250 deletions(-) delete mode 100644 djangular/static/js/app.js delete mode 100644 djangular/static/js/controllers.js delete mode 100644 djangular/static/js/directives.js delete mode 100644 djangular/static/js/services.js diff --git a/.gitignore b/.gitignore index f84e705..65421a3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ *.sublime-* *.sqlite3* *.sass-cache +*app.js +*services.js +*controllers.js +*directives.js /node_modules diff --git a/djangular/static/js/app.js b/djangular/static/js/app.js deleted file mode 100644 index 2507a93..0000000 --- a/djangular/static/js/app.js +++ /dev/null @@ -1,63 +0,0 @@ -(function() { - var app; - - app = angular.module('pollApp', ['ui.router', 'pollApp.controllers', 'pollApp.services', 'pollApp.directives']); - - app.config(function($interpolateProvider, $stateProvider, $urlRouterProvider) { - $interpolateProvider.startSymbol('[['); - $interpolateProvider.endSymbol(']]'); - $urlRouterProvider.otherwise('/'); - return $stateProvider.state('questionList', { - url: '/', - templateUrl: 'questionList', - controller: 'questionListController', - resolve: { - questions: function(Questions) { - Questions.fetch(); - return Questions.data(); - } - } - }).state('questionDetail', { - url: '/{questionId:[0-9]+}/', - templateUrl: 'questionDetail', - controller: 'questionDetailController', - resolve: { - question: function($stateParams, $log, Question) { - var question; - question = new Question(null); - question.get($stateParams.questionId); - return question; - } - } - }).state('questionResults', { - url: '/{questionId:[0-9]+}/results', - templateUrl: 'questionResults', - controller: 'questionResultsController', - resolve: { - question: function($stateParams, $log, Question) { - var question; - question = new Question(null); - question.get($stateParams.questionId); - return question; - } - } - }); - }); - - app.config(function($httpProvider) { - var getCookie; - getCookie = function(name) { - var cookie, _i, _len, _ref; - _ref = document.cookie.split(';'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - cookie = _ref[_i]; - if (cookie && name === (cookie.trim().split('='))[0]) { - return decodeURIComponent(cookie.trim().slice(1 + name.length)); - } - } - return null; - }; - return $httpProvider.defaults.headers.common['X-CSRFToken'] = getCookie("csrftoken"); - }); - -}).call(this); diff --git a/djangular/static/js/controllers.js b/djangular/static/js/controllers.js deleted file mode 100644 index e18df6c..0000000 --- a/djangular/static/js/controllers.js +++ /dev/null @@ -1,35 +0,0 @@ -(function() { - var controllers; - - controllers = angular.module('pollApp.controllers', []); - - controllers.controller('questionListController', function($scope, $state, $log, questions) { - return $scope.questions = questions.all; - }); - - controllers.controller('questionDetailController', function($scope, $state, $log, question) { - $scope.question = question; - $scope.voteChoice = 0; - return $scope.vote = function() { - var choice, _i, _len, _ref; - _ref = $scope.question.choices; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - choice = _ref[_i]; - if (choice.id === parseInt($scope.voteChoice)) { - choice.votes += 1; - $scope.question.totalVotes += 1; - choice.update(); - break; - } - } - return $state.go('questionResults', { - questionId: question.id - }); - }; - }); - - controllers.controller('questionResultsController', function($scope, $state, $log, question) { - return $scope.question = question; - }); - -}).call(this); diff --git a/djangular/static/js/directives.js b/djangular/static/js/directives.js deleted file mode 100644 index bee7b30..0000000 --- a/djangular/static/js/directives.js +++ /dev/null @@ -1,34 +0,0 @@ -(function() { - var directives; - - directives = angular.module('pollApp.directives', []); - - directives.directive('choicePercentage', function() { - return { - restrict: 'A', - scope: { - votes: '=', - total: '=' - }, - link: function(scope, element, attrs) { - var update; - update = function() { - var percentage; - if (scope.total > 0) { - percentage = scope.votes / scope.total * 100; - } else { - percentage = 0; - } - return element.css('width', percentage + '%'); - }; - scope.$watch('total', function(value) { - return update(); - }); - return scope.$watch('votes', function(value) { - return update(); - }); - } - }; - }); - -}).call(this); diff --git a/djangular/static/js/services.js b/djangular/static/js/services.js deleted file mode 100644 index 28f3280..0000000 --- a/djangular/static/js/services.js +++ /dev/null @@ -1,118 +0,0 @@ -(function() { - var services; - - services = angular.module('pollApp.services', []); - - services.factory('Choice', function($http, $log) { - var Choice; - Choice = (function() { - function Choice(data) { - this.choice_text = data.choice_text; - this.id = data.id; - this.votes = data.votes; - } - - Choice.prototype.update = function() { - var data, - _this = this; - data = { - 'votes': this.votes, - 'choice_text': this.choice_text - }; - return $http({ - method: 'PUT', - url: '/polls/choices/' + this.id + '/', - data: data - }).success(function(data) { - return $log.info("Succesfully voted"); - }).error(function(data) { - return $log.info("Failed to vote."); - }); - }; - - return Choice; - - })(); - return Choice; - }); - - services.factory('Question', function(Choice, $http, $log) { - var Question; - Question = (function() { - function Question(data) { - if (data !== null) { - this.init(data); - } - } - - Question.prototype.init = function(data) { - var c, choice, _i, _len, _ref, _results; - this.question_text = data.question_text; - this.id = data.id; - this.choices = []; - this.totalVotes = 0; - _ref = data.choices; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - choice = _ref[_i]; - c = new Choice(choice); - this.totalVotes += c.votes; - _results.push(this.choices.push(new Choice(choice))); - } - return _results; - }; - - Question.prototype.get = function(questionId) { - var _this = this; - return $http({ - method: 'GET', - url: '/polls/questions/' + questionId + '/' - }).success(function(data) { - _this.init(data); - return $log.info("Succesfully fetched question"); - }).error(function(data) { - return $log.info("Failed to fetch question."); - }); - }; - - return Question; - - })(); - return Question; - }); - - services.factory('Questions', function($log, $http, Question) { - var questions; - questions = { - all: [] - }; - return { - fromServer: function(data) { - var question, _i, _len, _results; - questions['all'].length = 0; - _results = []; - for (_i = 0, _len = data.length; _i < _len; _i++) { - question = data[_i]; - _results.push(questions['all'].push(new Question(question))); - } - return _results; - }, - fetch: function() { - var _this = this; - return $http({ - method: 'GET', - url: '/polls/questions' - }).success(function(data) { - _this.fromServer(data); - return $log.info("Succesfully fetched questions."); - }).error(function(data) { - return $log.info("Failed to fetch questions."); - }); - }, - data: function() { - return questions; - } - }; - }); - -}).call(this); From 494976ad8884373f1a1c38cae0a553d3c4222574 Mon Sep 17 00:00:00 2001 From: Mortonian Date: Thu, 26 Feb 2015 15:15:22 -0500 Subject: [PATCH 04/14] Backend for per-question Feedback --- djangular/polls/admin.py | 9 +++++++-- djangular/polls/models.py | 9 +++++++++ djangular/polls/serializers.py | 11 +++++++++-- djangular/polls/urls.py | 5 ++++- djangular/polls/views.py | 19 +++++++++++++++++-- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/djangular/polls/admin.py b/djangular/polls/admin.py index a8ebcca..8672da7 100644 --- a/djangular/polls/admin.py +++ b/djangular/polls/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from polls.models import Choice, Question +from polls.models import Choice, Question, Feedback class ChoiceInline(admin.StackedInline): @@ -7,12 +7,17 @@ class ChoiceInline(admin.StackedInline): extra = 3 +class FeedbackInline(admin.StackedInline): + model = Feedback + extra = 1 + + class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), ] - inlines = [ChoiceInline] + inlines = [ChoiceInline, FeedbackInline] admin.site.register(Question, QuestionAdmin) \ No newline at end of file diff --git a/djangular/polls/models.py b/djangular/polls/models.py index f45c090..bc7010f 100644 --- a/djangular/polls/models.py +++ b/djangular/polls/models.py @@ -16,3 +16,12 @@ class Choice(models.Model): def __unicode__(self): return self.choice_text + +class Feedback(models.Model): + question = models.ForeignKey(Question, related_name='feedbacks') + feedback_text = models.CharField(max_length=500) + pub_date = models.DateTimeField('date published') + + def __unicode__(self): + return self.feedback_text + diff --git a/djangular/polls/serializers.py b/djangular/polls/serializers.py index 2a10139..cf00cbc 100644 --- a/djangular/polls/serializers.py +++ b/djangular/polls/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Question, Choice +from .models import Question, Choice, Feedback class ChoiceSerializer(serializers.ModelSerializer): @@ -8,10 +8,17 @@ class Meta: model = Choice fields = ('choice_text', 'id', 'votes') +class FeedbackSerializer(serializers.ModelSerializer): + + class Meta: + model = Feedback + fields = ('feedback_text', 'id', 'pub_date') + class QuestionSerializer(serializers.ModelSerializer): choices = ChoiceSerializer(many=True) + feedbacks = FeedbackSerializer(many=True) class Meta: model = Question - fields = ('question_text', 'choices', 'id') + fields = ('question_text', 'choices', 'feedbacks', 'id') diff --git a/djangular/polls/urls.py b/djangular/polls/urls.py index 8797535..05f265d 100644 --- a/djangular/polls/urls.py +++ b/djangular/polls/urls.py @@ -1,6 +1,6 @@ from django.conf.urls import patterns, url, include -from .views import QuestionList, ChoiceList, QuestionDetail, ChoiceUpdate +from .views import QuestionList, ChoiceList, QuestionDetail, ChoiceUpdate, FeedbackList, FeedbackUpdate urlpatterns = patterns('polls.views', @@ -10,5 +10,8 @@ url(r'^choices$', ChoiceList.as_view(), name='choices_list'), url(r'^choices/(?P[0-9]+)/$', ChoiceUpdate.as_view(), name='choices_update'), + url(r'^feedbacks$', FeedbackList.as_view(), name='choices_list'), + url(r'^feedbacks/(?P[0-9]+)/$', FeedbackUpdate.as_view(), + name='feedback_update'), url(r'^$', 'index', name='questions_index'), ) diff --git a/djangular/polls/views.py b/djangular/polls/views.py index bb31838..ea241f2 100644 --- a/djangular/polls/views.py +++ b/djangular/polls/views.py @@ -1,6 +1,6 @@ from rest_framework import generics, permissions -from .models import Question, Choice -from .serializers import QuestionSerializer, ChoiceSerializer +from .models import Question, Choice, Feedback +from .serializers import QuestionSerializer, ChoiceSerializer, FeedbackSerializer from django.shortcuts import render @@ -38,5 +38,20 @@ class ChoiceList(generics.ListCreateAPIView): permissions.AllowAny ] +class FeedbackUpdate(generics.UpdateAPIView): + queryset = Feedback.objects.all() + serializer_class = FeedbackSerializer + lookup_url_kwarg = 'feedback_pk' + permission_classes = [ + permissions.AllowAny + ] + +class FeedbackList(generics.ListCreateAPIView): + queryset = Feedback.objects.all() + serializer_class = FeedbackSerializer + permission_classes = [ + permissions.AllowAny + ] + def index(request): return render(request, 'polls/index.html') From cfeaff481d68e42eeee9323d8d26b48fbcaa1c71 Mon Sep 17 00:00:00 2001 From: Mortonian Date: Thu, 26 Feb 2015 17:21:36 -0500 Subject: [PATCH 05/14] ng services and read-only view for feedback --- djangular/frontend/services.coffee | 24 +++++++++++++++++++++++- djangular/templates/polls/index.html | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/djangular/frontend/services.coffee b/djangular/frontend/services.coffee index 7193d14..ac8ae2d 100644 --- a/djangular/frontend/services.coffee +++ b/djangular/frontend/services.coffee @@ -19,7 +19,26 @@ services.factory('Choice', ($http, $log)-> return Choice ) -services.factory('Question', (Choice, $http, $log) -> +services.factory('Feedback', ($http, $log)-> + #log = $log + class Feedback + constructor: (data) -> + @feedback_text = data.feedback_text + @id = data.id + @pub_date = data.pub_date + + update : -> + data = {'feedback_text' : @feedback_text} + $http({method: 'PUT', url: '/polls/feedbacks/' + @id + '/', data:data}) + .success (data) => + $log.info("Succesfully left feedback") + .error (data) => + $log.info("Failed to leave feedback.") + + return Feedback +) + +services.factory('Question', (Choice, Feedback, $http, $log) -> class Question constructor : (data) -> if data != null @@ -28,11 +47,14 @@ services.factory('Question', (Choice, $http, $log) -> @question_text = data.question_text @id = data.id @choices = [] + @feedbacks = [] @totalVotes = 0 for choice in data.choices c = new Choice(choice) @totalVotes += c.votes @choices.push(new Choice(choice)) + for feedback in data.feedbacks + @feedbacks.push(new Feedback(feedback)) get : (questionId) -> $http({method: 'GET', url: '/polls/questions/' + questionId + '/'}) diff --git a/djangular/templates/polls/index.html b/djangular/templates/polls/index.html index 86bceac..47350f4 100644 --- a/djangular/templates/polls/index.html +++ b/djangular/templates/polls/index.html @@ -53,6 +53,28 @@

[[question.question_text]]

+
+
Feedback on this question
+
    +
  • + [[feedback.feedback_text]] +
    + -- Submitted at [[feedback.pub_date]] +
    +
  • +
  • +
    +
    Leave us feedback on this question
    +
    +