Merge pull request #11 from skiprope/subscriptions

Support for post subscriptions
This commit is contained in:
Georg G. 2015-04-21 14:28:36 +02:00
commit 2992cba387
19 changed files with 250 additions and 8 deletions

View File

@ -198,6 +198,45 @@ namespace :justask do
puts "Purged #{destroyed_count} dead notifications."
end
desc "Subscribes everyone to their answers"
task fix_submarines: :enviornment do
format = '%t (%c/%C) [%b>%i] %e'
total = Answer.count
progress = ProgressBar.create title: 'Processing answers', format: format, starting_at: 0, total: total
subscribed = 0
Answer.all.each do |a|
if not s.user.nil? and not s.answer.nil?
Subscription.subscribe a.user, a
subscribed += 1
end
progress.increment
end
puts "Subscribed to #{subscribed} posts."
end
desc "Destroy lost subscriptions"
task fix_torpedoes: :enviornment do
format = '%t (%c/%C) [%b>%i] %e'
total = Subscription.count
progress = ProgressBar.create title: 'Processing subscriptions', format: format, starting_at: 0, total: total
destroyed = 0
Subscription.all.each do |s|
if s.user.nil? or s.answer.nil?
s.destroy
destroyed += 1
end
progress.increment
end
puts "Put #{destroyed} subscriptions up for adoption."
end
desc "Fixes everything else"
task fix_db: :environment do
format = '%t (%c/%C) [%b>%i] %e'
@ -206,7 +245,8 @@ namespace :justask do
question: 0,
answer: 0,
smile: 0,
comment: 0
comment: 0,
subscription: 0
}
total = Inbox.count
@ -250,10 +290,24 @@ namespace :justask do
progress.increment
end
total = Subscription.count
progress = ProgressBar.create title: 'Processing subscriptions', format: format, starting_at: 0, total: total
Subscription.all.each do |s|
if s.user.nil? or s.answer.nil?
s.destroy
destroyed_count[:subscription] += 1
end
progress.increment
end
puts "Put #{destroyed} subscriptions up for adoption."
puts "Purged #{destroyed_count[:inbox]} dead inbox entries."
puts "Marked #{destroyed_count[:question]} questions as anonymous."
puts "Purged #{destroyed_count[:answer]} dead answers."
puts "Purged #{destroyed_count[:answer]} dead comments."
puts "Purged #{destroyed_count[:subscription]} dead subscriptions."
end
desc "Prints lonely people."

View File

@ -39,6 +39,9 @@ $(document).on "keyup", "input[name=ab-comment-new]", (evt) ->
input.val ''
ctr.html 160
$("span#ab-comment-count-#{aid}").html data.count
subs = $("a[data-action=ab-submarine][data-a-id=#{aid}]")[0]
subs.dataset.torpedo = "no"
subs.children[0].nextSibling.textContent = "Unsubscribe"
showNotification data.message, data.success
error: (jqxhr, status, error) ->
console.log jqxhr, status, error

View File

@ -0,0 +1,27 @@
# the laziest coding known to man
$(document).on "click", "a[data-action=ab-submarine]", (ev) ->
ev.preventDefault()
btn = $(this)
aid = btn[0].dataset.aId
torpedo = 0
if btn[0].dataset.torpedo == "yes"
torpedo = 1
endpoint = "subscribe"
if torpedo == 0
endpoint = "un" + endpoint
$.ajax
url: '/ajax/' + endpoint # TODO: find a way to use rake routes instead of hardcoding them here
type: 'POST'
data:
answer: aid
success: (data, status, jqxhr) ->
if data.success
btn[0].dataset.torpedo = ["yes", "no"][torpedo]
btn[0].children[0].nextSibling.textContent = ["Subscribe", "Unsubscribe"][torpedo]
showNotification "Successfully " + endpoint + "d.", true
else
showNotification "Couldn't unsubscribe from the answer.", false
error: (jqxhr, status, error) ->
console.log jqxhr, status, error
showNotification "An error occurred, a developer should check the console for details", false
complete: (jqxhr, status) ->

View File

@ -0,0 +1,19 @@
class Ajax::SubscriptionController < ApplicationController
before_filter :authenticate_user!
def subscribe
params.require :answer
@status = 418
@message = "418 I'm a torpedo"
state = Subscription.subscribe(current_user, Answer.find(params[:answer])).nil?
@success = state == false
end
def unsubscribe
params.require :answer
@status = 418
@message = "418 I'm a torpedo"
state = Subscription.unsubscribe(current_user, Answer.find(params[:answer])).nil?
@success = state == false
end
end

View File

@ -0,0 +1,2 @@
module SubscribeHelper
end

View File

@ -3,11 +3,14 @@ class Answer < ActiveRecord::Base
belongs_to :question
has_many :comments, dependent: :destroy
has_many :smiles, dependent: :destroy
has_many :subscriptions, dependent: :destroy
after_create do
Inbox.where(user: self.user, question: self.question).destroy_all
Notification.notify self.question.user, self unless self.question.author_is_anonymous
Subscription.subscribe self.user, self
Subscription.subscribe self.question.user, self
self.user.increment! :answered_count
self.question.increment! :answer_count
end
@ -27,9 +30,10 @@ class Answer < ActiveRecord::Base
end
self.comments.each do |comment|
comment.user.decrement! :commented_count
Notification.denotify self.user, comment
Subscription.denotify comment, self
end
Notification.denotify self.question.user, self
Subscription.destruct self
end
def notification_type(*_args)

View File

@ -7,14 +7,15 @@ class Comment < ActiveRecord::Base
validates :content, length: { maximum: 160 }
after_create do
Notification.notify answer.user, self unless answer.user == self.user
Subscription.subscribe self.user, answer, false
Subscription.notify self, answer
user.increment! :commented_count
answer.increment! :comment_count
end
before_destroy do
Notification.denotify answer.user, self unless answer.user == self.user
user.decrement! :commented_count
Subscription.denotify self, answer
user.decrement! :commented_count
answer.decrement! :comment_count
end

View File

@ -0,0 +1,69 @@
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :answer
class << self
def for(target)
Subscription.where(answer: target)
end
def is_subscribed(recipient, target)
existing = Subscription.find_by(user: recipient, answer: target)
existing.nil? or existing.is_active
end
def subscribe(recipient, target, force = true)
existing = Subscription.find_by(user: recipient, answer: target)
if existing.nil?
Subscription.new(user: recipient, answer: target).save!
elsif force
existing.update(is_active: true)
end
end
def unsubscribe(recipient, target)
if recipient.nil? or target.nil?
return nil
end
subs = Subscription.find_by(user: recipient, answer: target)
subs.update(is_active: false) unless subs.nil?
end
def destruct(target)
if target.nil?
return nil
end
Subscription.where(answer: target).destroy_all
end
def destruct_by(recipient, target)
if recipient.nil? or target.nil?
return nil
end
subs = Subscription.find_by(user: recipient, answer: target)
subs.destroy unless subs.nil?
end
def notify(source, target)
if source.nil? or target.nil?
return nil
end
Subscription.where(answer: target, is_active: true).each do |subs|
next unless not subs.user == source.user
Notification.notify subs.user, source
end
end
def denotify(source, target)
if source.nil? or target.nil?
return nil
end
Subscription.where(answer: target).each do |subs|
Notification.denotify subs.user, source
end
end
end
end

View File

@ -28,6 +28,8 @@ class User < ActiveRecord::Base
has_many :groups, dependent: :destroy
has_many :group_memberships, class_name: "GroupMember", foreign_key: 'user_id', dependent: :destroy
has_many :subscriptions, dependent: :destroy
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/
WEBSITE_REGEX = /https?:\/\/([A-Za-z.\-]+)\/?(?:.*)/i

View File

@ -0,0 +1 @@
json.partial! 'ajax/shared/status'

View File

@ -0,0 +1 @@
json.partial! 'ajax/shared/status'

View File

@ -53,7 +53,13 @@
%p.notification--text
commented on
%a{href: show_user_answer_path(username: notification.target.user.screen_name, id: notification.target.answer.id), title: "#{notification.target.answer.content[0..40]}...", data: { toggle: :tooltip, placement: :top }}
your answer
- if notification.target.answer.user == current_user
your
- elsif notification.target.user == notification.target.answer.user
their
- else
= user_screen_name(notification.target.answer.user, false, false) + "'s"
answer
%span{title: notification.target.created_at, data: { toggle: :tooltip, placement: :bottom }}
= time_ago_in_words notification.target.created_at
ago

View File

@ -21,6 +21,17 @@
%button.btn.btn-default.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
%span.caret
%ul.dropdown-menu.dropdown-menu-right{role: :menu}
- if Subscription.is_subscribed(current_user, a)
%li
-# fun joke should subscribe?
%a{href: '#', data: { a_id: a.id, action: 'ab-submarine', torpedo: "no" }}
%i.fa.fa-anchor
Unubscribe
- else
%li
%a{href: '#', data: { a_id: a.id, action: 'ab-submarine', torpedo: "yes" }}
%i.fa.fa-anchor
Subscribe
- if privileged? a.user
%li.text-danger
%a{href: '#', data: { a_id: a.id, action: 'ab-destroy' }}

View File

@ -82,6 +82,8 @@ Rails.application.routes.draw do
match '/destroy_group', to: 'group#destroy', via: :post, as: :destroy_group
match '/group_membership', to: 'group#membership', via: :post, as: :group_membership
match '/preview', to: "question#preview", via: :post, as: :preview
match '/subscribe', to: 'subscription#subscribe', via: :post, as: :subscribe_answer
match '/unsubscribe', to: 'subscription#unsubscribe', via: :post, as: :unsubscribe_answer
end
match '/public', to: 'public#index', via: :get, as: :public_timeline

View File

@ -0,0 +1,10 @@
class CreateSubscriptions < ActiveRecord::Migration
def change
create_table :subscriptions do |t|
t.integer :user_id, null: false
t.integer :answer_id, null: false
t.timestamps null: false
end
end
end

View File

@ -0,0 +1,5 @@
class AddIsActiveToSubscriptions < ActiveRecord::Migration
def change
add_column :subscriptions, :is_active, :boolean, default: :true
end
end

View File

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe SubscribeController, :type => :controller do
end

View File

@ -0,0 +1,15 @@
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the SubscribeHelper. For example:
#
# describe SubscribeHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe SubscribeHelper, :type => :helper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe Subscription, :type => :model do
pending "add some examples to (or delete) #{__FILE__}"
end