Commit e9745fa9 authored by mbajur's avatar mbajur
Browse files

Merge branch 'dev' into 'master'

0.6.0

See merge request prismosuite/prismo!225
parents 2888116b 2c721320
......@@ -74,6 +74,8 @@ gem 'redcarpet'
gem 'pg_search'
gem 'onebox'
gem 'rinku'
gem 'webmention'
gem 'webmention-endpoint'
group :development, :test do
gem 'dotenv-rails'
......@@ -90,7 +92,9 @@ group :development do
gem 'spring-commands-rspec'
gem 'foreman'
gem 'letter_opener'
gem 'slimkeyfy'
# gem 'slimkeyfy' # automatic slim translations. Conflicts with webmention
gem 'better_errors'
gem 'binding_of_caller'
end
group :test do
......
GEM
remote: https://rubygems.org/
specs:
absolutely (1.1.2)
addressable (~> 2.5)
actioncable (5.2.0)
actionpack (= 5.2.0)
nio4r (~> 2.0)
......@@ -72,7 +74,13 @@ GEM
aws-sigv4 (~> 1.0)
aws-sigv4 (1.0.3)
bcrypt (3.1.12)
better_errors (2.5.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.5.0)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootsnap (1.3.1)
msgpack (~> 1.0)
builder (3.2.3)
......@@ -98,6 +106,7 @@ GEM
closure_tree (7.0.0)
activerecord (>= 4.2.10)
with_advisory_lock (>= 4.0.0)
coderay (1.1.2)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
......@@ -110,6 +119,7 @@ GEM
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.4)
debug_inspector (0.0.3)
devise (4.4.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
......@@ -174,8 +184,7 @@ GEM
domain_name (~> 0.5)
http-form_data (2.1.1)
http_parser.rb (0.6.0)
httparty (0.16.4)
mime-types (~> 3.0)
httparty (0.15.7)
multi_xml (>= 0.5.2)
i18n (1.1.1)
concurrent-ruby (~> 1.0)
......@@ -236,9 +245,6 @@ GEM
meta-tags (2.10.0)
actionpack (>= 3.2.0, < 5.3)
method_source (0.9.0)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812)
mimemagic (0.3.2)
mini_magick (4.8.0)
mini_mime (1.0.0)
......@@ -362,8 +368,6 @@ GEM
ffi (~> 1.9)
ruby_dep (1.5.0)
rubyzip (1.2.1)
russian (0.6.0)
i18n (>= 0.5.0)
safe_yaml (1.0.4)
sanitize (4.6.6)
crass (~> 1.0.2)
......@@ -413,9 +417,6 @@ GEM
actionpack (>= 3.1)
railties (>= 3.1)
slim (~> 3.0)
slimkeyfy (0.1.0)
russian
yandex-translator
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
......@@ -461,6 +462,16 @@ GEM
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
webmention (0.1.6)
httparty (~> 0.15.5)
json
link_header (~> 0.0.8)
nokogiri
webmention-endpoint (2.0.0)
absolutely (~> 1.1)
addressable (~> 2.5, >= 2.5.2)
http (~> 3.3)
nokogiri (~> 1.8, >= 1.8.4)
webmock (3.4.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
......@@ -476,8 +487,6 @@ GEM
activerecord (>= 4.2)
xpath (3.1.0)
nokogiri (~> 1.8)
yandex-translator (0.3.2)
httparty (>= 0.13.4)
PLATFORMS
ruby
......@@ -486,6 +495,8 @@ DEPENDENCIES
active_interaction (~> 3.6)
active_link_to
aws-sdk-s3 (~> 1.2)
better_errors
binding_of_caller
bootsnap (>= 1.1.0)
bullet
byebug
......@@ -542,7 +553,6 @@ DEPENDENCIES
simplecov
site_prism (~> 2.15)
slim-rails
slimkeyfy
spring
spring-commands-rspec
spring-watcher-listen (~> 2.0.0)
......@@ -551,6 +561,8 @@ DEPENDENCIES
uglifier (>= 1.3.0)
validate_url
web-console (>= 3.3.0)
webmention
webmention-endpoint
webmock
webpacker
......
......@@ -2,19 +2,25 @@
module Admin
class SettingsController < BaseController
ADMIN_SETTINGS = %w(
ADMIN_SETTINGS = %w[
site_title
site_description
stories_per_day
story_likes_per_day
comment_likes_per_day
open_registrations
webmentions_enabled
closed_registrations_message
story_title_update_time_limit
).freeze
edit_counter_grace_period_minutes
].freeze
BOOLEAN_SETTINGS = %w(open_registrations).freeze
UPLOAD_SETTINGS = %w().freeze
BOOLEAN_SETTINGS = %w[
open_registrations
webmentions_enabled
].freeze
UPLOAD_SETTINGS = %w[].freeze
def edit
authorize :admin
......
# frozen_string_literal: true
module Api
module Ujs
class TagsController < Api::Ujs::BaseController
def toggle_follow
user_needed
tag = find_tag
authorize tag
if current_account.following?(tag)
UnfollowService.new(current_account.object, tag).call
else
FollowService.new(current_account.object, tag).call
end
locals = {
presenter: FollowTagButtonPresenter.new(current_account.object, tag)
}
render 'tags/_follow_btn', layout: false, locals: locals
end
private
def find_tag
@find_tag ||= Gutentag::Tag.find_by!(id: params[:id])
end
end
end
end
# frozen_string_literal: true
class Dashboard::FollowedAccountsController < ApplicationController
class DashboardsController < ApplicationController
before_action :authenticate_user!
before_action :set_account_liked_story_ids
before_action { set_jumpbox_link(Jumpbox::FOLLOWED_USERS_LINK) }
before_action { set_jumpbox_link(Jumpbox::DASHBOARD_LINK) }
def show
@page_title = 'Hot stories'
stories = StoriesQuery.new.hot
stories = StoriesQuery.new(stories).by_followed_accounts(current_account)
stories = StoriesQuery.new(stories).for_dashboard(current_account)
@stories = stories.page(params[:page])
end
......@@ -19,7 +19,7 @@ class Dashboard::FollowedAccountsController < ApplicationController
@page_title = 'Recent stories'
stories = StoriesQuery.new.recent
stories = StoriesQuery.new(stories).by_followed_accounts(current_account)
stories = StoriesQuery.new(stories).for_dashboard(current_account)
@stories = stories.page(params[:page])
......
# frozen_string_literal: true
module Settings
class PreferencesController < ApplicationController
before_action :authenticate_user!
layout 'settings'
def show
@preferences = Settings::UpdatePreferencesForm.new(user: current_user)
end
def update
@preferences = Settings::UpdatePreferencesForm.run(
settings_params.merge(user: current_user)
)
if @preferences.valid?
redirect_to settings_preferences_path, notice: 'Preferences updated'
else
render :show
end
end
private
def settings_params
params.require(:settings).permit(:theme)
end
end
end
......@@ -40,6 +40,6 @@ class Settings::ProfilesController < ApplicationController
private
def account_params
params.require(:account).permit(:display_name, :bio, :avatar, :remove_avatar)
params.require(:account).permit(:display_name, :bio, :avatar, :remove_avatar, :theme)
end
end
# frozen_string_literal: true
class StoryDecorator < Draper::Decorator
include Rails.application.routes.url_helpers
delegate_all
def to_s
......@@ -15,6 +17,10 @@ class StoryDecorator < Draper::Decorator
h.story_path(object)
end
def local_url
story_url(object)
end
def domain
return nil if !object.url.present?
URI.parse(object.url).host
......@@ -55,7 +61,7 @@ class StoryDecorator < Draper::Decorator
title: object.title,
description: excerpt,
alternate: [{
href: h.story_url(object), type: 'application/activity+json'
href: local_url, type: 'application/activity+json'
}],
og: {
title: object.title,
......
# frozen_string_literal: true
module ApplicationHelper
def current_user_setting(setting)
return unless current_user.present?
current_user.settings.send(setting.to_sym)
end
end
# frozen_string_literal: true
class Comments::Update < ActiveInteraction::Base
object :comment
string :body
module Comments
class Update < ActiveInteraction::Base
object :comment
string :body
def execute
comment.body = body if body?
def execute
comment.body = body if body?
comment.modified_at = Time.current
comment.modified_count += 1
comment.modified_at = Time.current
comment.modified_count += 1 if edit_grace_period_passed?
if comment.save
after_comment_save_hook(comment)
else
errors.merge!(comment.errors)
if comment.save
after_comment_save_hook(comment)
else
errors.merge!(comment.errors)
end
comment
end
comment
end
def persisted?
true
end
def persisted?
true
end
private
private
def after_comment_save_hook(comment)
comment.cache_body
Comments::BroadcastChanges.run! comment: comment
ActivityPub::UpdateDistributionJob.call_later(comment) if comment.local?
end
def after_comment_save_hook(comment)
comment.cache_body
Comments::BroadcastChanges.run! comment: comment
ActivityPub::UpdateDistributionJob.call_later(comment) if comment.local?
def edit_grace_period_passed?
period = Setting.edit_counter_grace_period_minutes
period.minutes.ago > comment.created_at
end
end
end
# frozen_string_literal: true
module Settings
class UpdatePreferencesForm < ActiveInteraction::Base
THEMES = %w[default dark].freeze
object :user
string :theme
validates :theme, presence: true
validates :theme, allow_blank: true, inclusion: { in: THEMES }
def initialize(args)
self.theme ||= args[:user].settings.theme || THEMES.first
super
end
def execute
user.settings.theme = theme if theme?
end
end
end
......@@ -2,35 +2,42 @@
require 'active_interaction'
class Stories::Create < Stories::CreateUpdateBase
validates :url, url: { allow_blank: true }
validate :url_or_description_required
def execute
story = Story.new(inputs)
story.account = account
story.url_domain = URI.parse(url).host if url.present?
story.group = Group.find_by!(supergroup: true)
story.tag_names = tags
story.local = true
if story.save
after_story_save_hook(story)
else
errors.merge!(story.errors)
module Stories
class Create < Stories::CreateUpdateBase
validates :url, url: { allow_blank: true }
validate :url_or_description_required
def execute
story = Story.new(inputs)
story.account = account
story.url_domain = URI.parse(url).host if url.present?
story.group = Group.find_by!(supergroup: true)
story.tag_names = tags
story.local = true
if story.save
after_story_save_hook(story)
else
errors.merge!(story.errors)
end
story
end
story
end
private
private
def after_story_save_hook(story)
account.touch(:last_active_at)
def after_story_save_hook(story)
account.touch(:last_active_at)
Stories::Like.run!(story: story, account: account)
Stories::ScrapJob.perform_later(story.id)
Stories::SendWebmentionJob.perform_later(story.id) if send_webmention?(story)
ActivityPub::DistributionJob.call(story)
end
Stories::Like.run!(story: story, account: account)
Stories::ScrapJob.perform_later(story.id)
ActivityPub::DistributionJob.call(story)
def send_webmention?(story)
story.link? && story.local? && Setting.webmentions_enabled
end
end
end
# frozen_string_literal: true
class Stories::Update < Stories::CreateUpdateBase
object :story
module Stories
class Update < CreateUpdateBase
object :story
validates :url, url: { allow_blank: true }
validate :url_or_description_required
validate :title_update_time_limit
validates :url, url: { allow_blank: true }
validate :url_or_description_required
validate :title_update_time_limit
def execute
story.title = title if title?
story.tag_names = tags if tag_list?
story.description = description if description?
story.url = url if url.present? && can_update_url?
def execute
story.title = title if title?
story.tag_names = tags if tag_list?
story.description = description if description?
story.url = url if url.present? && can_update_url?
story.modified_at = Time.current
story.modified_count += 1
story.modified_at = Time.current
story.modified_count += 1 if edit_grace_period_passed?
if story.save
after_story_save_hook(story)
else
errors.merge!(story.errors)
if story.save
after_story_save_hook(story)
else
errors.merge!(story.errors)
end
story
end
story
end
def persisted?
true
end
def persisted?
true
end
private
private
def after_story_save_hook(story)
Stories::ScrapJob.perform_later(story.id) if story.url_changed?
Stories::BroadcastChanges.run!(story: story)
ActivityPub::UpdateDistributionJob.call_later(story) if story.local?
end
def after_story_save_hook(story)
Stories::ScrapJob.perform_later(story.id) if story.url_changed?
Stories::BroadcastChanges.run!(story: story)
ActivityPub::UpdateDistributionJob.call_later(story) if story.local?
end
def title_update_time_limit
return unless title_changed?
def title_update_time_limit
return unless title_changed?
limit = Setting.story_title_update_time_limit
errors.add(:title, "can't be edited after #{limit} minutes") unless can_update_title?
end
limit = Setting.story_title_update_time_limit
errors.add(:title, "can't be edited after #{limit} minutes") unless can_update_title?
end
def title_changed?
title? && title != story.title
end
def title_changed?
title? && title != story.title
end
def can_update_title?
StoryPolicy.new(account.user, story).update_title?
end
def can_update_title?
StoryPolicy.new(account.user, story).update_title?
end
def can_update_url?
Stories::UpdatePolicy.new(account.user, story).update_url?
end
def can_update_url?
Stories::UpdatePolicy.new(account.user, story).update_url?
def edit_grace_period_passed?
period = Setting.edit_counter_grace_period_minutes
period.to_i.minutes.ago > story.created_at
end
end
end
......@@ -46,26 +46,9 @@
--color-grey-dark: hsl(210, 16%, 66%);
--color-grey-darker: hsl(210, 16%, 56%);
// color primary
--color-primary-lighter: hsl(231, 51%, 80%);
--color-primary-light: hsl(231, 51%, 70%);
--color-primary: hsl(231, 51%, 60%);
--color-primary-dark: hsl(231, 51%, 50%);
--color-primary-darker: hsl(231, 51%, 40%);
--color-primary-a10: hsla(231, 51%, 60%, 0.1);
// color contrasts
--color-bg: hsl(0, 0%, 98%);
--color-contrast-lower: hsl(240, 4%, 95%);
--color-contrast-low-l: hsl(220, 9%, 90%);
--color-contrast-low: hsl(220, 9%, 87%);
--color-contrast-medium-l: hsl(222, 9%, 73%);