mirror of
https://github.com/Retrospring/retrospring.git
synced 2024-11-20 14:29:53 +01:00
Merge branch 'main' into feature/lists-tuuuuuurbo
This commit is contained in:
commit
54bf109fc5
33 changed files with 177 additions and 340 deletions
18
Gemfile.lock
18
Gemfile.lock
|
@ -85,14 +85,14 @@ GEM
|
|||
rack (>= 0.9.0)
|
||||
binding_of_caller (1.0.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.14.0)
|
||||
bootsnap (1.15.0)
|
||||
msgpack (~> 1.2)
|
||||
bootstrap_form (4.5.0)
|
||||
actionpack (>= 5.2)
|
||||
activemodel (>= 5.2)
|
||||
buftok (0.2.0)
|
||||
builder (3.2.4)
|
||||
bullet (7.0.3)
|
||||
bullet (7.0.4)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
carrierwave (2.1.0)
|
||||
|
@ -183,7 +183,7 @@ GEM
|
|||
glob (0.3.1)
|
||||
globalid (1.0.0)
|
||||
activesupport (>= 5.0)
|
||||
haml (6.0.10)
|
||||
haml (6.0.12)
|
||||
temple (>= 0.8.2)
|
||||
thor
|
||||
tilt
|
||||
|
@ -307,7 +307,7 @@ GEM
|
|||
pundit (2.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
questiongenerator (1.0.0)
|
||||
racc (1.6.0)
|
||||
racc (1.6.1)
|
||||
rack (2.2.4)
|
||||
rack-protection (2.2.2)
|
||||
rack
|
||||
|
@ -425,13 +425,13 @@ GEM
|
|||
sprockets-rails
|
||||
tilt
|
||||
semantic_range (3.0.0)
|
||||
sentry-rails (5.6.0)
|
||||
sentry-rails (5.7.0)
|
||||
railties (>= 5.0)
|
||||
sentry-ruby (~> 5.6.0)
|
||||
sentry-ruby (5.6.0)
|
||||
sentry-ruby (~> 5.7.0)
|
||||
sentry-ruby (5.7.0)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
sentry-sidekiq (5.6.0)
|
||||
sentry-ruby (~> 5.6.0)
|
||||
sentry-sidekiq (5.7.0)
|
||||
sentry-ruby (~> 5.7.0)
|
||||
sidekiq (>= 3.0)
|
||||
shoulda-matchers (5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Ajax::AnonymousBlockController < AjaxController
|
||||
def create
|
||||
params.require :question
|
||||
|
||||
question = Question.find(params[:question])
|
||||
|
||||
raise Errors::Forbidden if params[:global] && !current_user.mod?
|
||||
|
||||
AnonymousBlock.create!(
|
||||
user: params[:global] ? nil : current_user,
|
||||
identifier: question.author_identifier,
|
||||
question:
|
||||
)
|
||||
|
||||
question.inboxes.first&.destroy
|
||||
|
||||
@response[:status] = :okay
|
||||
@response[:message] = t(".success")
|
||||
@response[:success] = true
|
||||
end
|
||||
|
||||
def destroy
|
||||
params.require :id
|
||||
|
||||
block = AnonymousBlock.find(params[:id])
|
||||
if current_user != block.user
|
||||
@response[:status] = :nopriv
|
||||
@response[:message] = t(".nopriv")
|
||||
end
|
||||
|
||||
block.destroy!
|
||||
|
||||
@response[:status] = :okay
|
||||
@response[:message] = t(".success")
|
||||
@response[:success] = true
|
||||
end
|
||||
end
|
46
app/controllers/anonymous_block_controller.rb
Normal file
46
app/controllers/anonymous_block_controller.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AnonymousBlockController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
def create
|
||||
params.require :question
|
||||
|
||||
question = Question.find(params[:question])
|
||||
authorize AnonymousBlock, :create_global? if params[:global]
|
||||
|
||||
AnonymousBlock.create!(
|
||||
user: params[:global] ? nil : current_user,
|
||||
identifier: question.author_identifier,
|
||||
question:
|
||||
)
|
||||
|
||||
inbox_id = question.inboxes.first.id
|
||||
question.inboxes.first&.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.turbo_stream do
|
||||
render turbo_stream: turbo_stream.remove("inbox_#{inbox_id}")
|
||||
end
|
||||
|
||||
format.html { redirect_back(fallback_location: inbox_path) }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
params.require :id
|
||||
|
||||
block = AnonymousBlock.find(params[:id])
|
||||
authorize block
|
||||
|
||||
block.destroy!
|
||||
|
||||
respond_to do |format|
|
||||
format.turbo_stream do
|
||||
render turbo_stream: turbo_stream.remove("block_#{params[:id]}")
|
||||
end
|
||||
|
||||
format.html { redirect_back(fallback_location: settings_blocks_path) }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,7 +49,11 @@ class InboxController < ApplicationController
|
|||
@disabled = true if @inbox.empty?
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.turbo_stream { render "show", layout: false, status: :see_other }
|
||||
format.turbo_stream do
|
||||
render "show", layout: false, status: :see_other
|
||||
|
||||
@inbox.update_all(new: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -33,15 +33,6 @@ module ApplicationHelper
|
|||
!current_user.nil? && ((current_user == user) || current_user.mod?)
|
||||
end
|
||||
|
||||
def ios_web_app?
|
||||
user_agent = request.env["HTTP_USER_AGENT"] || "Mozilla/5.0"
|
||||
# normal MobileSafari.app UA: Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B435 Safari/600.1.4
|
||||
# webapp UA: Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B435
|
||||
return true if user_agent.match(/^Mozilla\/\d+\.\d+ \(i(?:Phone|Pad|Pod); CPU(?:.*) like Mac OS X\)(?:.*) Mobile(?:\S*)$/)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def rails_admin_path_for_resource(resource)
|
||||
[rails_admin_path, resource.model_name.param_key, resource.id].join("/")
|
||||
end
|
||||
|
|
|
@ -4,7 +4,6 @@ import { Application } from '@hotwired/stimulus';
|
|||
import { definitionsFromContext } from '@hotwired/stimulus-webpack-helpers';
|
||||
|
||||
import start from 'retrospring/common';
|
||||
import initAnnouncements from 'retrospring/features/announcement';
|
||||
import initAnswerbox from 'retrospring/features/answerbox/index';
|
||||
import initInbox from 'retrospring/features/inbox/index';
|
||||
import initUser from 'retrospring/features/user';
|
||||
|
@ -27,7 +26,6 @@ document.addEventListener('turbo:load', initQuestionbox);
|
|||
document.addEventListener('DOMContentLoaded', initQuestion);
|
||||
document.addEventListener('DOMContentLoaded', initModeration);
|
||||
document.addEventListener('DOMContentLoaded', initMemes);
|
||||
document.addEventListener('turbo:load', initAnnouncements);
|
||||
document.addEventListener('turbo:load', initLocales);
|
||||
document.addEventListener('turbo:load', initFront);
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
export default class extends Controller {
|
||||
static values = {
|
||||
id: Number
|
||||
};
|
||||
|
||||
declare readonly idValue: number;
|
||||
|
||||
connect(): void {
|
||||
if (!window.localStorage.getItem(`announcement${this.idValue}`)) {
|
||||
this.element.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
window.localStorage.setItem(`announcement${this.idValue}`, 'true');
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export default function (event: Event): void {
|
||||
const announcement = (event.target as HTMLElement).closest(".announcement") as HTMLDivElement;
|
||||
const announcementId = announcement.dataset.announcementId;
|
||||
window.localStorage.setItem(`announcement${announcementId}`, 'true');
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import registerEvents from 'utilities/registerEvents';
|
||||
import closeAnnouncementHandler from './close';
|
||||
|
||||
export default (): void => {
|
||||
registerEvents([
|
||||
{ type: 'click', target: document.querySelector('.announcement button.close'), handler: closeAnnouncementHandler },
|
||||
]);
|
||||
|
||||
document.querySelectorAll('.announcement').forEach(function (el: HTMLDivElement) {
|
||||
if (!window.localStorage.getItem(`announcement${el.dataset.announcementId}`)) {
|
||||
el.classList.remove('d-none');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import { post } from '@rails/request.js';
|
||||
|
||||
import { showErrorNotification, showNotification } from "utilities/notifications";
|
||||
import I18n from "retrospring/i18n";
|
||||
|
||||
export function blockAnonEventHandler(event: Event): void {
|
||||
const element: HTMLAnchorElement = event.target as HTMLAnchorElement;
|
||||
|
||||
const data = {
|
||||
question: element.getAttribute('data-q-id'),
|
||||
};
|
||||
|
||||
post('/ajax/block_anon', {
|
||||
body: data,
|
||||
contentType: 'application/json'
|
||||
})
|
||||
.then(async response => {
|
||||
const data = await response.json;
|
||||
|
||||
if (!data.success) return false;
|
||||
const inboxEntry: Node = element.closest('.inbox-entry');
|
||||
|
||||
showNotification(data.message);
|
||||
|
||||
(inboxEntry as HTMLElement).remove();
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
showErrorNotification(I18n.translate('frontend.error.message'));
|
||||
});
|
||||
}
|
|
@ -3,15 +3,13 @@ import { answerEntryHandler, answerEntryInputHandler } from './answer';
|
|||
import { deleteEntryHandler } from './delete';
|
||||
import optionsEntryHandler from './options';
|
||||
import { reportEventHandler } from './report';
|
||||
import { blockAnonEventHandler } from "retrospring/features/inbox/entry/blockAnon";
|
||||
|
||||
export default (): void => {
|
||||
registerEvents([
|
||||
{ type: 'click', target: 'button[name="ib-answer"]', handler: answerEntryHandler, global: true },
|
||||
{ type: 'click', target: '[name="ib-destroy"]', handler: deleteEntryHandler, global: true },
|
||||
{ type: 'click', target: '[name=ib-report]', handler: reportEventHandler, global: true },
|
||||
{ type: 'click', target: '[name=ib-block-anon]', handler: blockAnonEventHandler, global: true },
|
||||
{ type: 'click', target: 'button[name=ib-options]', handler: optionsEntryHandler, global: true },
|
||||
{ type: 'keydown', target: 'textarea[name=ib-answer]', handler: answerEntryInputHandler, global: true }
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import { post } from '@rails/request.js';
|
||||
import swal from 'sweetalert';
|
||||
|
||||
import { showErrorNotification, showNotification } from "utilities/notifications";
|
||||
import I18n from "retrospring/i18n";
|
||||
|
||||
export function blockAnonEventHandler(event: Event): void {
|
||||
event.preventDefault();
|
||||
|
||||
swal({
|
||||
title: I18n.translate('frontend.mod_mute.confirm.title'),
|
||||
text: I18n.translate('frontend.mod_mute.confirm.text'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: I18n.translate('voc.y'),
|
||||
cancelButtonText: I18n.translate('voc.n'),
|
||||
closeOnConfirm: true,
|
||||
}, (dialogResult) => {
|
||||
if (!dialogResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sender: HTMLAnchorElement = event.target as HTMLAnchorElement;
|
||||
|
||||
const data = {
|
||||
question: sender.getAttribute('data-q-id'),
|
||||
global: 'true'
|
||||
};
|
||||
|
||||
post('/ajax/block_anon', {
|
||||
body: data,
|
||||
contentType: 'application/json'
|
||||
})
|
||||
.then(async response => {
|
||||
const data = await response.json;
|
||||
|
||||
if (!data.success) return false;
|
||||
|
||||
showNotification(data.message);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
showErrorNotification(I18n.translate('frontend.error.message'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -2,15 +2,13 @@ import registerEvents from 'utilities/registerEvents';
|
|||
import { banCheckboxHandler, banFormHandler, permanentBanCheckboxHandler } from './ban';
|
||||
import { destroyReportHandler } from './destroy';
|
||||
import { privilegeCheckHandler } from './privilege';
|
||||
import { blockAnonEventHandler } from './blockAnon';
|
||||
|
||||
export default (): void => {
|
||||
registerEvents([
|
||||
{ type: 'click', target: '[type="checkbox"][name="check-your-privileges"]', handler: privilegeCheckHandler, global: true },
|
||||
{ type: 'click', target: '[name="mod-delete-report"]', handler: destroyReportHandler, global: true },
|
||||
{ type: 'click', target: '[name="mod-block-anon"]', handler: blockAnonEventHandler, global: true },
|
||||
{ type: 'change', target: '[name="ban"][type="checkbox"]', handler: banCheckboxHandler, global: true },
|
||||
{ type: 'change', target: '[name="permaban"][type="checkbox"]', handler: permanentBanCheckboxHandler, global: true },
|
||||
{ type: 'submit', target: '#modal-ban form', handler: banFormHandler, global: true }
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import { destroy } from '@rails/request.js';
|
||||
import { showNotification, showErrorNotification } from 'utilities/notifications';
|
||||
import I18n from 'retrospring/i18n';
|
||||
|
||||
export function unblockAnonymousHandler(event: Event): void {
|
||||
const button: HTMLButtonElement = event.currentTarget as HTMLButtonElement;
|
||||
const targetId = button.dataset.target;
|
||||
|
||||
destroy(`/ajax/block_anon/${targetId}`)
|
||||
.then(async response => {
|
||||
if (!response.ok) return;
|
||||
|
||||
const data = await response.json;
|
||||
showNotification(data.message, data.success);
|
||||
button.closest('.list-group-item').remove();
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
showErrorNotification(I18n.translate('frontend.error.message'));
|
||||
});
|
||||
}
|
|
@ -2,7 +2,6 @@ import registerEvents from "utilities/registerEvents";
|
|||
import { profileHeaderChangeHandler, profilePictureChangeHandler } from "./crop";
|
||||
import { themeDocumentHandler, themeSubmitHandler } from "./theme";
|
||||
import { userSubmitHandler } from "./password";
|
||||
import { unblockAnonymousHandler } from "./block";
|
||||
|
||||
export default (): void => {
|
||||
themeDocumentHandler();
|
||||
|
@ -11,7 +10,6 @@ export default (): void => {
|
|||
{ type: 'submit', target: document.querySelector('form.edit_theme, form.new_theme'), handler: themeSubmitHandler },
|
||||
{ type: 'submit', target: document.querySelector('#edit_user'), handler: userSubmitHandler },
|
||||
{ type: 'change', target: document.querySelector('#user_profile_picture[type=file]'), handler: profilePictureChangeHandler },
|
||||
{ type: 'change', target: document.querySelector('#user_profile_header[type=file]'), handler: profileHeaderChangeHandler },
|
||||
{ type: 'click', target: document.querySelectorAll('[data-action="anon-unblock"]'), handler: unblockAnonymousHandler }
|
||||
{ type: 'change', target: document.querySelector('#user_profile_header[type=file]'), handler: profileHeaderChangeHandler }
|
||||
]);
|
||||
}
|
||||
|
|
18
app/policies/anonymous_block_policy.rb
Normal file
18
app/policies/anonymous_block_policy.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AnonymousBlockPolicy
|
||||
attr_reader :user, :anonymous_block
|
||||
|
||||
def initialize(user, anonymous_block)
|
||||
@user = user
|
||||
@anonymous_block = anonymous_block
|
||||
end
|
||||
|
||||
def create_global?
|
||||
user.mod?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user == anonymous_block.user || user.mod?
|
||||
end
|
||||
end
|
|
@ -8,11 +8,11 @@
|
|||
%i.fa.fa-fw.fa-exclamation-triangle
|
||||
= t("voc.report")
|
||||
- if question.anonymous? && !question.generated?
|
||||
%a.dropdown-item{ name: "ib-block-anon", data: { q_id: question.id } }
|
||||
= button_to anonymous_block_path, method: :post, params: { question: question.id }, class: "dropdown-item" do
|
||||
%i.fa.fa-fw.fa-minus-circle
|
||||
= t("voc.block")
|
||||
- if current_user.mod?
|
||||
%a.dropdown-item{ href: "#", name: "mod-block-anon", data: { q_id: question.id } }
|
||||
= button_to anonymous_block_path, method: :post, params: { question: question.id, global: true }, class: "dropdown-item" do
|
||||
%i.fa.fa-fw.fa-volume-off
|
||||
= t("voc.block_site_wide")
|
||||
%a.dropdown-item{ href: moderation_questions_path(author_identifier: question.author_identifier) }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.card.inbox-entry{ class: i.new? ? "inbox-entry--new" : "", data: { id: i.id } }
|
||||
.card.inbox-entry{ id: "inbox_#{i.id}", class: i.new? ? "inbox-entry--new" : "", data: { id: i.id } }
|
||||
.card-header
|
||||
.media
|
||||
- unless i.question.author_is_anonymous
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
= render 'shared/links'
|
||||
|
||||
:ruby
|
||||
Inbox.where(id: @inbox.ids).update_all(new: false)
|
||||
@inbox.update_all(new: false)
|
||||
provide(:title, generate_title('Inbox'))
|
||||
parent_layout 'base'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%nav.navbar.navbar-themed.navbar-expand-lg.bg-primary.fixed-top.d-lg-block.d-none.d-print-none{ role: :navigation }
|
||||
.container{ class: ios_web_app? ? 'ios-web-app' : '' }
|
||||
.container
|
||||
%a.navbar-brand{ href: '/', title: APP_CONFIG["site_name"] }
|
||||
- if APP_CONFIG["use_svg_logo"]
|
||||
= render inline: Rails.application.config.justask_svg_logo
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%nav.navbar.navbar-themed.navbar-expand-lg.bg-primary.fixed-top{ role: :navigation }
|
||||
.container{ class: ios_web_app? ? 'ios-web-app' : '' }
|
||||
.container
|
||||
%a.navbar-brand{ href: '/', title: APP_CONFIG["site_name"] }
|
||||
- if APP_CONFIG["use_svg_logo"]
|
||||
= render inline: Rails.application.config.justask_svg_logo
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
= render 'navigation/dropdown/notifications', notifications: notifications, size: "mobile"
|
||||
- notifications_icon = notification_count.nil? ? 'bell-o' : 'bell'
|
||||
%nav.navbar.navbar-themed.bg-primary.fixed-bottom.d-lg-none.d-block.d-print-none#rs-mobile-nav{ role: :navigation }
|
||||
.container{ class: ios_web_app? ? 'ios-web-app' : '' }
|
||||
.container
|
||||
%ul.nav.navbar-nav.navbar-icon-row
|
||||
= nav_entry t("navigation.timeline"), root_path, icon: 'home', icon_only: true
|
||||
= nav_entry t("navigation.inbox"), '/inbox',
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
.dropdown-menu.dropdown-menu-right.notification-dropdown{ id: "rs-#{size}-nav-notifications" }
|
||||
- if notifications.count.zero?
|
||||
.dropdown-item.text-center.p-2
|
||||
%i.fa.fa-bell-o.notification__bell-icon
|
||||
%p= t(".none")
|
||||
%a.dropdown-item.text-center{ href: notifications_path('all') }
|
||||
%i.fa.fa-fw.fa-chevron-right
|
||||
= t(".all")
|
||||
.dropdown-item.text-center.p-2
|
||||
%i.fa.fa-bell-o.notification__bell-icon
|
||||
%p= t(".none")
|
||||
- else
|
||||
%a.dropdown-item.text-center{ href: notifications_path }
|
||||
%i.fa.fa-fw.fa-chevron-right
|
||||
= t(".new")
|
||||
- notifications.each do |notification|
|
||||
.dropdown-item
|
||||
= render "notifications/type/#{notification.target.class.name.downcase.split('::').last}", notification: notification
|
||||
|
||||
%a.dropdown-item.text-center{ href: notifications_path }
|
||||
%i.fa.fa-fw.fa-chevron-right
|
||||
= t(".new")
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.announcement__container
|
||||
- @active_announcements.each do |announcement|
|
||||
.alert.announcement.alert-info.alert-dismissable.d-none{ data: { 'announcement-id': announcement.id } }
|
||||
.alert.announcement.alert-info.alert-dismissable.d-none{ data: { controller: 'announcement', "announcement-id-value": announcement.id } }
|
||||
.container
|
||||
%button.close{ type: :button, data: { dismiss: :alert } }
|
||||
%button.close{ type: :button, data: { dismiss: :alert, action: "click->announcement#close" } }
|
||||
%span{ aria: { hidden: true } } ×
|
||||
%p
|
||||
= announcement.content
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%li.list-group-item
|
||||
%li.list-group-item{ id: "block_#{block.id}" }
|
||||
.d-flex
|
||||
%div
|
||||
- if block.question.present?
|
||||
|
@ -7,5 +7,5 @@
|
|||
%p.mb-0.text-muted.font-italic= t(".deleted_question")
|
||||
%p.text-muted.mb-0= t(".blocked", time: time_ago_in_words(block.created_at))
|
||||
.ml-auto.d-inline-flex
|
||||
%button.btn.btn-default.align-self-center{ data: { action: "anon-unblock", target: block.id } }
|
||||
%span.pe-none= t("voc.unblock")
|
||||
= button_to anonymous_block_path, method: :delete, params: { id: block.id }, class: "btn btn-default align-self-center" do
|
||||
%span.pe-none= t("voc.unblock")
|
||||
|
|
|
@ -132,12 +132,11 @@ Rails.application.routes.draw do
|
|||
post "/list_membership", to: "list#membership", as: :list_membership
|
||||
post "/subscribe", to: "subscription#subscribe", as: :subscribe_answer
|
||||
post "/unsubscribe", to: "subscription#unsubscribe", as: :unsubscribe_answer
|
||||
post "/block_anon", to: "anonymous_block#create", as: :block_anon
|
||||
delete "/block_anon/:id", to: "anonymous_block#destroy", as: :unblock_anon
|
||||
end
|
||||
|
||||
post "/lists", to: "lists#index", as: :lists
|
||||
delete "/lists/:list", to: "lists#destroy", as: :lists_destroy
|
||||
resource :anonymous_block, controller: :anonymous_block, only: %i[create destroy]
|
||||
|
||||
get "/discover", to: "discover#index", as: :discover
|
||||
match "/public", to: "timeline#public", via: [:get, :post], as: :public_timeline if APP_CONFIG.dig(:features, :public, :enabled)
|
||||
|
|
|
@ -133,7 +133,7 @@ class Exporter
|
|||
end
|
||||
|
||||
def publish
|
||||
`tar czvf #{Rails.root.join "public", "export", "#{@export_filename}.tar.gz"} -C /tmp/rs_export #{@export_dirname}`
|
||||
`tar czvf #{Rails.public_path.join "export", "#{@export_filename}.tar.gz"} #{@export_dirname}`
|
||||
url = "#{APP_CONFIG['https'] ? 'https' : 'http'}://#{APP_CONFIG['hostname']}/export/#{@export_filename}.tar.gz"
|
||||
@user.export_processing = false
|
||||
@user.export_url = url
|
||||
|
|
|
@ -15,9 +15,9 @@ module Retrospring
|
|||
|
||||
def year = 2022
|
||||
|
||||
def month = 11
|
||||
def month = 12
|
||||
|
||||
def day = 20
|
||||
def day = 4
|
||||
|
||||
def patch = 0
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@hotwired/stimulus": "^3.1.1",
|
||||
"@hotwired/stimulus": "^3.2.1",
|
||||
"@hotwired/stimulus-webpack-helpers": "^1.0.1",
|
||||
"@fontsource/lexend": "^4.5.13",
|
||||
"@hotwired/turbo-rails": "^7.2.4",
|
||||
|
@ -27,7 +27,7 @@
|
|||
"typescript": "^4.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.2",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@rails/webpacker": "5.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
require "rails_helper"
|
||||
|
||||
describe Ajax::AnonymousBlockController, :ajax_controller, type: :controller do
|
||||
describe AnonymousBlockController, type: :controller do
|
||||
describe "#create" do
|
||||
subject { post(:create, params: params) }
|
||||
subject { post(:create, params:) }
|
||||
|
||||
context "user signed in" do
|
||||
let(:user) { FactoryBot.create(:user) }
|
||||
|
@ -20,19 +20,9 @@ describe Ajax::AnonymousBlockController, :ajax_controller, type: :controller do
|
|||
{ question: question.id }
|
||||
end
|
||||
|
||||
let(:expected_response) do
|
||||
{
|
||||
"success" => true,
|
||||
"status" => "okay",
|
||||
"message" => anything
|
||||
}
|
||||
end
|
||||
|
||||
it "creates an anonymous block" do
|
||||
expect { subject }.to(change { AnonymousBlock.count }.by(1))
|
||||
end
|
||||
|
||||
include_examples "returns the expected response"
|
||||
end
|
||||
|
||||
context "when blocking a user globally" do
|
||||
|
@ -43,14 +33,6 @@ describe Ajax::AnonymousBlockController, :ajax_controller, type: :controller do
|
|||
end
|
||||
|
||||
context "as a moderator" do
|
||||
let(:expected_response) do
|
||||
{
|
||||
"success" => true,
|
||||
"status" => "okay",
|
||||
"message" => anything
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
user.add_role(:moderator)
|
||||
end
|
||||
|
@ -59,48 +41,19 @@ describe Ajax::AnonymousBlockController, :ajax_controller, type: :controller do
|
|||
expect { subject }.to(change { AnonymousBlock.count }.by(1))
|
||||
expect(AnonymousBlock.last.user_id).to be_nil
|
||||
end
|
||||
|
||||
include_examples "returns the expected response"
|
||||
end
|
||||
|
||||
context "as a regular user" do
|
||||
let(:expected_response) do
|
||||
{
|
||||
"success" => false,
|
||||
"status" => "forbidden",
|
||||
"message" => anything
|
||||
}
|
||||
end
|
||||
|
||||
it "does not create an anonymous block" do
|
||||
expect { subject }.not_to(change { AnonymousBlock.count })
|
||||
expect { subject }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
include_examples "returns the expected response"
|
||||
end
|
||||
end
|
||||
|
||||
context "when parameters are missing" do
|
||||
let(:params) { {} }
|
||||
let(:expected_response) do
|
||||
{
|
||||
"success" => false,
|
||||
"status" => "parameter_error",
|
||||
"message" => anything
|
||||
}
|
||||
end
|
||||
|
||||
it "does not create an anonymous block" do
|
||||
expect { subject }.not_to(change { AnonymousBlock.count })
|
||||
end
|
||||
|
||||
include_examples "returns the expected response"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#destroy" do
|
||||
subject { delete(:destroy, params: params) }
|
||||
subject { delete(:destroy, params:) }
|
||||
|
||||
context "user signed in" do
|
||||
let(:user) { FactoryBot.create(:user) }
|
||||
|
@ -111,20 +64,16 @@ describe Ajax::AnonymousBlockController, :ajax_controller, type: :controller do
|
|||
|
||||
context "when all parameters are given" do
|
||||
let(:question) { FactoryBot.create(:question, author_identifier: "someidentifier") }
|
||||
let(:block) { AnonymousBlock.create(user: user, identifier: "someidentifier", question: question) }
|
||||
let(:block) { AnonymousBlock.create(user:, identifier: "someidentifier", question:) }
|
||||
let(:params) do
|
||||
{ id: block.id }
|
||||
end
|
||||
|
||||
let(:expected_response) do
|
||||
{
|
||||
"success" => true,
|
||||
"status" => "okay",
|
||||
"message" => anything
|
||||
}
|
||||
end
|
||||
it "destroys the anonymous block" do
|
||||
subject
|
||||
|
||||
include_examples "returns the expected response"
|
||||
expect(AnonymousBlock.exists?(block.id)).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -87,32 +87,6 @@ describe ApplicationHelper, type: :helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#ios_web_app" do
|
||||
context "Non-iOS device" do
|
||||
it "should not return true" do
|
||||
controller.request.user_agent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2;"
|
||||
|
||||
expect(helper.ios_web_app?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "iOS device (not in web app mode)" do
|
||||
it "should not return true" do
|
||||
controller.request.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B435 Safari/600.1.4"
|
||||
|
||||
expect(helper.ios_web_app?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "iOS device" do
|
||||
it "should return true" do
|
||||
controller.request.user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B435"
|
||||
|
||||
expect(helper.ios_web_app?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#rails_admin_path_for_resource" do
|
||||
context "user resource" do
|
||||
let(:resource) { FactoryBot.create(:user) }
|
||||
|
|
|
@ -296,11 +296,13 @@ RSpec.describe Exporter do
|
|||
|
||||
describe "#publish" do
|
||||
let(:fake_rails_root) { Pathname(Dir.mktmpdir) }
|
||||
let(:fake_rails_public_path) { fake_rails_root.join('public') }
|
||||
let(:name) { instance.instance_variable_get(:@export_filename) }
|
||||
|
||||
before do
|
||||
FileUtils.mkdir_p("#{fake_rails_root}/public/export")
|
||||
allow(Rails).to receive(:root).and_return(fake_rails_root)
|
||||
allow(Rails).to receive(:public_path).and_return(fake_rails_public_path)
|
||||
|
||||
user.export_processing = true
|
||||
user.save!
|
||||
|
|
84
yarn.lock
84
yarn.lock
|
@ -34,33 +34,33 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
|
||||
integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==
|
||||
|
||||
"@babel/core@^7.15.0", "@babel/core@^7.20.2":
|
||||
version "7.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.2.tgz#8dc9b1620a673f92d3624bd926dc49a52cf25b92"
|
||||
integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==
|
||||
"@babel/core@^7.15.0", "@babel/core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.5.tgz#45e2114dc6cd4ab167f81daf7820e8fa1250d113"
|
||||
integrity sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.1.0"
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.20.2"
|
||||
"@babel/generator" "^7.20.5"
|
||||
"@babel/helper-compilation-targets" "^7.20.0"
|
||||
"@babel/helper-module-transforms" "^7.20.2"
|
||||
"@babel/helpers" "^7.20.1"
|
||||
"@babel/parser" "^7.20.2"
|
||||
"@babel/helpers" "^7.20.5"
|
||||
"@babel/parser" "^7.20.5"
|
||||
"@babel/template" "^7.18.10"
|
||||
"@babel/traverse" "^7.20.1"
|
||||
"@babel/types" "^7.20.2"
|
||||
"@babel/traverse" "^7.20.5"
|
||||
"@babel/types" "^7.20.5"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/generator@^7.20.1", "@babel/generator@^7.20.2":
|
||||
version "7.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.2.tgz#c2e89e22613a039285c1e7b749e2cd0b30b9a481"
|
||||
integrity sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==
|
||||
"@babel/generator@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95"
|
||||
integrity sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.20.2"
|
||||
"@babel/types" "^7.20.5"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
|
@ -366,14 +366,14 @@
|
|||
"@babel/traverse" "^7.18.11"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/helpers@^7.20.1":
|
||||
version "7.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.1.tgz#2ab7a0fcb0a03b5bf76629196ed63c2d7311f4c9"
|
||||
integrity sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==
|
||||
"@babel/helpers@^7.20.5":
|
||||
version "7.20.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.6.tgz#e64778046b70e04779dfbdf924e7ebb45992c763"
|
||||
integrity sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==
|
||||
dependencies:
|
||||
"@babel/template" "^7.18.10"
|
||||
"@babel/traverse" "^7.20.1"
|
||||
"@babel/types" "^7.20.0"
|
||||
"@babel/traverse" "^7.20.5"
|
||||
"@babel/types" "^7.20.5"
|
||||
|
||||
"@babel/highlight@^7.10.4":
|
||||
version "7.16.7"
|
||||
|
@ -393,10 +393,10 @@
|
|||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
|
||||
version "7.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.2.tgz#9aeb9b92f64412b5f81064d46f6a1ac0881337f4"
|
||||
integrity sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==
|
||||
"@babel/parser@^7.18.10", "@babel/parser@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
|
||||
integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
|
||||
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
|
@ -1050,26 +1050,26 @@
|
|||
"@babel/parser" "^7.18.10"
|
||||
"@babel/types" "^7.18.10"
|
||||
|
||||
"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.11", "@babel/traverse@^7.18.6", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1":
|
||||
version "7.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
|
||||
integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
|
||||
"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.11", "@babel/traverse@^7.18.6", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
|
||||
integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.20.1"
|
||||
"@babel/generator" "^7.20.5"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-function-name" "^7.19.0"
|
||||
"@babel/helper-hoist-variables" "^7.18.6"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/parser" "^7.20.1"
|
||||
"@babel/types" "^7.20.0"
|
||||
"@babel/parser" "^7.20.5"
|
||||
"@babel/types" "^7.20.5"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.16.7", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.4.4":
|
||||
version "7.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842"
|
||||
integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==
|
||||
"@babel/types@^7.16.7", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
|
||||
integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.19.4"
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
|
@ -1115,10 +1115,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd"
|
||||
integrity sha512-wa/zupVG0eWxRYJjC1IiPBdt3Lruv0RqGN+/DTMmUWUyMAEB27KXmVY6a8YpUVTM7QwVuaLNGW4EqDgrS2upXQ==
|
||||
|
||||
"@hotwired/stimulus@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.1.1.tgz#652f08a8e1d5edcb407340e58818fcff463b5848"
|
||||
integrity sha512-e0JpzIaYLsRRXevRDVs0yevabiCvieIWWCwh7VqVXjXM5AOHdjb7AjaKIj34zYFmY1N6HIRRfk915WVMYlHnDA==
|
||||
"@hotwired/stimulus@^3.2.1":
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.1.tgz#e3de23623b0c52c247aba4cd5d530d257008676b"
|
||||
integrity sha512-HGlzDcf9vv/EQrMJ5ZG6VWNs8Z/xMN+1o2OhV1gKiSG6CqZt5MCBB1gRg5ILiN3U0jEAxuDTNPRfBcnZBDmupQ==
|
||||
|
||||
"@hotwired/turbo-rails@^7.1.0", "@hotwired/turbo-rails@^7.2.4":
|
||||
version "7.2.4"
|
||||
|
@ -2984,9 +2984,9 @@ decamelize@^1.2.0:
|
|||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
|
||||
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
|
||||
|
||||
deep-is@^0.1.3:
|
||||
version "0.1.4"
|
||||
|
|
Loading…
Reference in a new issue