Compare commits
3 Commits
allow-unde
...
improve-do
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bda6c3480 | ||
|
|
98afad4174 | ||
|
|
3471e21429 |
@@ -1,4 +1,8 @@
|
|||||||
$(document).on("click", "[data-behavior=play_recording]", function() {
|
$(document).on("click", "[data-behavior=play_recording]", function() {
|
||||||
|
if ($(this).hasClass('active')){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$("#broadcast_video").data('videoType', 'recording');
|
$("#broadcast_video").data('videoType', 'recording');
|
||||||
|
|
||||||
var playback_url = $(this).attr("data-playback-url")
|
var playback_url = $(this).attr("data-playback-url")
|
||||||
@@ -12,6 +16,13 @@ $(document).on("click", "[data-behavior=play_recording]", function() {
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
autoPlay: true
|
autoPlay: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".dropdown-menu").children().removeClass('active');
|
||||||
|
$(".dropdown-menu").children().children('i').remove();
|
||||||
|
$(this).siblings().removeClass('active');
|
||||||
|
$(this).siblings().children("i").remove();
|
||||||
|
$(this).addClass('active');
|
||||||
|
$(this).prepend('<i class="fa fa-check"> </i>');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", "[data-behavior=play_stream]", function() { $("#broadcast_video").data('videoType', 'stream'); });
|
$(document).on("click", "[data-behavior=play_stream]", function() { $("#broadcast_video").data('videoType', 'stream'); });
|
||||||
@@ -1,30 +1,4 @@
|
|||||||
// Do not allow file attachments in rich text content
|
// Do not allow file attachments in rich text content
|
||||||
addEventListener("trix-file-accept", function(event) {
|
addEventListener("trix-file-accept", function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
})
|
||||||
|
|
||||||
Trix.config.textAttributes.underline = {
|
|
||||||
style: { "textDecoration": "underline" },
|
|
||||||
inheritable: true,
|
|
||||||
parser: function (element) {
|
|
||||||
var style = window.getComputedStyle(element);
|
|
||||||
return style.textDecoration === "underline";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('trix-initialize', function (e) {
|
|
||||||
const trix = e.target;
|
|
||||||
const toolBar = trix.toolbarElement;
|
|
||||||
|
|
||||||
// // Creation of the button
|
|
||||||
const button = document.createElement("button");
|
|
||||||
button.setAttribute("type", "button");
|
|
||||||
button.setAttribute("class", "trix-button trix-button--icon trix-button--icon-underline");
|
|
||||||
button.setAttribute("data-trix-attribute", "underline");
|
|
||||||
button.setAttribute("title", "underline");
|
|
||||||
button.setAttribute("tabindex", "-1");
|
|
||||||
button.innerText = "U";
|
|
||||||
|
|
||||||
// Attachment of the button to the toolBar
|
|
||||||
toolBar.querySelector('.trix-button-group--text-tools').appendChild(button);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -461,10 +461,3 @@ a[data-behavior=seekable-timecode] {
|
|||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-bottom: 3px solid #ff0000;
|
border-bottom: 3px solid #ff0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Trix underline style
|
|
||||||
trix-toolbar {
|
|
||||||
.trix-button--icon-underline::before {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z'/%3E%3C/svg%3E");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,14 +45,13 @@ class Api::ReleasesController < Api::ApiController
|
|||||||
if model_name == "acquired_media_release"
|
if model_name == "acquired_media_release"
|
||||||
mapping = {
|
mapping = {
|
||||||
"#{model_name.camelize}": SerializableAcquiredMediaRelease,
|
"#{model_name.camelize}": SerializableAcquiredMediaRelease,
|
||||||
FileInfo: SerializableFileInfo,
|
FileInfo: SerializableFileInfo
|
||||||
"ActiveStorage::Attachment".to_sym => ActiveStorage::SerializableAttachment,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render jsonapi: release,
|
render jsonapi: release,
|
||||||
status: status,
|
status: status,
|
||||||
class: mapping,
|
class: mapping,
|
||||||
include: [:files, :file_infos]
|
include: [:file_infos]
|
||||||
else
|
else
|
||||||
mapping = {
|
mapping = {
|
||||||
"#{model_name.camelize}": show_serializable,
|
"#{model_name.camelize}": show_serializable,
|
||||||
|
|||||||
@@ -4,16 +4,4 @@ class PagesController < ApplicationController
|
|||||||
skip_after_action :verify_authorized
|
skip_after_action :verify_authorized
|
||||||
skip_after_action :verify_policy_scoped
|
skip_after_action :verify_policy_scoped
|
||||||
skip_before_action :require_login
|
skip_before_action :require_login
|
||||||
|
|
||||||
layout :layout_for_page
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def layout_for_page
|
|
||||||
case params[:id]
|
|
||||||
when 'nanocosmos_player'
|
|
||||||
false
|
|
||||||
else
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ class BroadcastRecordingPolicy < ApplicationPolicy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit?
|
def edit?
|
||||||
true
|
destroy?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update?
|
def update?
|
||||||
true
|
edit?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,14 +17,4 @@ class SerializableAcquiredMediaRelease < JSONAPI::Serializable::Resource
|
|||||||
{ count: @object.file_infos.size }
|
{ count: @object.file_infos.size }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
has_many :files do
|
|
||||||
data do
|
|
||||||
@object.files
|
|
||||||
end
|
|
||||||
|
|
||||||
meta do
|
|
||||||
{ count: @object.files.size }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
class SerializableUser < JSONAPI::Serializable::Resource
|
class SerializableUser < JSONAPI::Serializable::Resource
|
||||||
type "user"
|
type "user"
|
||||||
|
|
||||||
attributes :email, :full_name
|
attributes :email
|
||||||
|
|
||||||
attribute :company_name do
|
|
||||||
@object.primary_account.name
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<% recordings.each do |recording| %>
|
<% recordings.each do |recording| %>
|
||||||
<div class="list-group-item list-group-item-action">
|
<div class="list-group-item list-group-item-action">
|
||||||
<div class="d-flex align-items-start">
|
<div class="d-flex align-items-start">
|
||||||
<% if policy(BroadcastRecording).update? %>
|
<% if (controller.class.module_parent.to_s != "Public" && policy(BroadcastRecording).update?) %>
|
||||||
<%= link_to fa_icon("#{recording.starred ? 'star' : 'star-o'} fw"), [broadcast.project, broadcast, recording, :broadcast_recording_starrings], method: :post, class: "text-warning mr-3", remote: true %>
|
<%= link_to fa_icon("#{recording.starred ? 'star' : 'star-o'} fw"), [broadcast.project, broadcast, recording, :broadcast_recording_starrings], method: :post, class: "text-warning mr-3", remote: true %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= image_tag(recording.thumbnail_url, class: 'img-thumbnail img-fluid max-w-75', data: { behavior: "play_recording", playback_url: recording.playback_url, id: dom_id(recording) }) %>
|
<%= image_tag(recording.thumbnail_url, class: 'img-thumbnail img-fluid max-w-75') %>
|
||||||
<div class="ml-auto">
|
<div class="ml-auto">
|
||||||
<% if policy(BroadcastRecording).edit? %>
|
<% if (controller.class.module_parent.to_s != "Public" && policy(BroadcastRecording).edit?) %>
|
||||||
<%= link_to fa_icon('edit'), [:edit, broadcast.project, broadcast, recording], remote: true %>
|
<%= link_to fa_icon('edit'), [:edit, broadcast.project, broadcast, recording], remote: true %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= link_to(fa_icon('download'), recording.download_url, target: "_blank") %>
|
<%= link_to(fa_icon('download'), recording.download_url, target: "_blank") %>
|
||||||
|
|||||||
@@ -9,4 +9,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr/>
|
||||||
@@ -22,16 +22,11 @@
|
|||||||
<div class="d-flex justify-content-start align-items-center flex-row p-3 mb-5 bg-dark">
|
<div class="d-flex justify-content-start align-items-center flex-row p-3 mb-5 bg-dark">
|
||||||
<%= product_wordmark(:direct_me, class: 'navbar-brand text-white') %>
|
<%= product_wordmark(:direct_me, class: 'navbar-brand text-white') %>
|
||||||
<div class="ml-4 dropdown">
|
<div class="ml-4 dropdown">
|
||||||
<% if @multi_view_broadcasts.present? %>
|
<%= link_to "#", class: "btn btn-light dropdown-toggle text-white bg-black border-0 override-dropdown-show-state", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } do %>
|
||||||
<%= link_to "#", class: "btn btn-light dropdown-toggle text-white bg-black border-0 override-dropdown-show-state", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } do %>
|
<i class="fa fa-video-camera text-primary" aria-hidden="true"></i><span class="ml-2" id="selected_stream"><%= @broadcast.name %></span>
|
||||||
<i class="fa fa-video-camera text-primary" aria-hidden="true"></i><span class="ml-2" id="selected_stream"><%= @broadcast.name %></span>
|
|
||||||
<% end %>
|
|
||||||
<% else %>
|
|
||||||
<%= link_to "javascript:void(0);", class: "btn btn-light text-white bg-black border-0 override-dropdown-show-state", role: "button", id: "dropdownMenuLink", aria: { haspopup: "true", expanded: "false" } do %>
|
|
||||||
<i class="fa fa-video-camera text-primary" aria-hidden="true"></i><span class="ml-2" id="selected_stream"><%= @broadcast.name %></span>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="dropdown-menu bg-black" aria-labelledby="dropdownMenuLink">
|
<div class="dropdown-menu bg-black" aria-labelledby="dropdownMenuLink">
|
||||||
|
<h5 class="dropdown-header">Live Streams</h5>
|
||||||
<%= link_to fa_icon("check", text: @broadcast.name.titleize), "#", data: { behavior: "play_stream"}, class: "dropdown-item active" %>
|
<%= link_to fa_icon("check", text: @broadcast.name.titleize), "#", data: { behavior: "play_stream"}, class: "dropdown-item active" %>
|
||||||
<% @multi_view_broadcasts.each do |broadcast| %>
|
<% @multi_view_broadcasts.each do |broadcast| %>
|
||||||
<% if broadcast.id != @broadcast.id %>
|
<% if broadcast.id != @broadcast.id %>
|
||||||
@@ -125,21 +120,6 @@
|
|||||||
<div id="live_take">
|
<div id="live_take">
|
||||||
<%= render partial: 'broadcasts/live_take', locals: { broadcast: @broadcast } %>
|
<%= render partial: 'broadcasts/live_take', locals: { broadcast: @broadcast } %>
|
||||||
</div>
|
</div>
|
||||||
<% if params[:director_mode] %>
|
|
||||||
<% if controller.class.module_parent.to_s == "Public" %>
|
|
||||||
<%= link_to "Play #{@broadcast.name.titleize}", url_for(params.permit!.merge(director_mode: true, token: @broadcast.token)), data: { behavior: "play_stream"}, class: "mt-2 btn btn-primary" %>
|
|
||||||
<% else %>
|
|
||||||
<%= link_to "Play #{@broadcast.name.titleize}", url_for(params.permit!.merge(director_mode: true, id: @broadcast.id)), data: { behavior: "play_stream"}, class: "mt-2 btn btn-primary" %>
|
|
||||||
<% end %>
|
|
||||||
<hr/>
|
|
||||||
<% else %>
|
|
||||||
<% if controller.class.module_parent.to_s == "Public" %>
|
|
||||||
<%= link_to "Play #{@broadcast.name.titleize}", url_for(params.permit!.merge(token: @broadcast.token).except(:director_mode)), data: { behavior: "play_stream"}, class: "mt-2 btn btn-primary" %>
|
|
||||||
<% else %>
|
|
||||||
<%= link_to "Play #{@broadcast.name.titleize}", url_for(params.permit!.merge(id: @broadcast.id).except(:director_mode)), data: { behavior: "play_stream"}, class: "mt-2 btn btn-primary" %>
|
|
||||||
<% end %>
|
|
||||||
<hr/>
|
|
||||||
<% end %>
|
|
||||||
<div id="broadcast_recordings">
|
<div id="broadcast_recordings">
|
||||||
<%= render partial: 'broadcasts/broadcast_recordings', locals: { recordings: @recordings, broadcast: @broadcast } %>
|
<%= render partial: 'broadcasts/broadcast_recordings', locals: { recordings: @recordings, broadcast: @broadcast } %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div id="playerDiv"></div>
|
|
||||||
<script type="text/javascript" src="https://demo.nanocosmos.de/nanoplayer/api/release/nanoplayer.4.min.js"></script>
|
|
||||||
<%= javascript_tag nonce: true do %>
|
|
||||||
var urlParams = new URLSearchParams(window.location.search);
|
|
||||||
var streamName = urlParams.get('stream_name');
|
|
||||||
console.log("streamName", streamName);
|
|
||||||
var player;
|
|
||||||
var config = {
|
|
||||||
"source": {
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"h5live": {
|
|
||||||
// your rtmp stream
|
|
||||||
"rtmp": {
|
|
||||||
"url": "rtmp://bintu-play.nanocosmos.de/play",
|
|
||||||
"streamname": streamName,
|
|
||||||
},
|
|
||||||
"server": {
|
|
||||||
"websocket": "wss://bintu-h5live.nanocosmos.de:443/h5live/stream.mp4",
|
|
||||||
"hls": "https://bintu-h5live.nanocosmos.de:443/h5live/http/playlist.m3u8",
|
|
||||||
"progressive": "https://bintu-h5live.nanocosmos.de:443/h5live/http/stream.mp4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"width": "auto",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function initPlayer() {
|
|
||||||
player = new NanoPlayer('playerDiv');
|
|
||||||
player.setup(config).then(function (config) {
|
|
||||||
console.log('setup ok with config: ' + JSON.stringify(config));
|
|
||||||
}, function (error) {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// load player from playerDiv
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
initPlayer();
|
|
||||||
});
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
@@ -9,12 +9,12 @@ Rails.application.config.content_security_policy do |policy|
|
|||||||
policy.font_src :self, :https, :data
|
policy.font_src :self, :https, :data
|
||||||
policy.img_src :self, :https, :data
|
policy.img_src :self, :https, :data
|
||||||
policy.object_src :self
|
policy.object_src :self
|
||||||
policy.script_src :self, :https, AppHost.new.domain_with_port, "https://stream.mux.com", "https://demo.nanocosmos.de", :blob, :unsafe_eval
|
policy.script_src :self, :https, AppHost.new.domain_with_port, "https://stream.mux.com", :blob, :unsafe_eval
|
||||||
policy.media_src :self, :https, AppHost.new.domain_with_port, "https://stream.mux.com", :data, :blob
|
policy.media_src :self, :https, AppHost.new.domain_with_port, "https://stream.mux.com", :data, :blob
|
||||||
# policy.style_src :self, :https, :unsafe_inline
|
# policy.style_src :self, :https, :unsafe_inline
|
||||||
# If you are using webpack-dev-server then specify webpack-dev-server host
|
# If you are using webpack-dev-server then specify webpack-dev-server host
|
||||||
# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
|
# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
|
||||||
policy.connect_src :self, :https, "ws://#{AppHost.new.domain_with_port}", "wss://#{AppHost.new.domain_with_port}", "wss://bintu-h5live.nanocosmos.de"
|
policy.connect_src :self, :https, "ws://#{AppHost.new.domain_with_port}", "wss://#{AppHost.new.domain_with_port}"
|
||||||
|
|
||||||
# Specify URI for violation reports
|
# Specify URI for violation reports
|
||||||
# policy.report_uri "/csp-violation-report-endpoint"
|
# policy.report_uri "/csp-violation-report-endpoint"
|
||||||
|
|||||||
@@ -200,7 +200,6 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
get "cookies_disabled" => 'pages#show', id: "cookies_disabled", as: :cookies_disabled
|
get "cookies_disabled" => 'pages#show', id: "cookies_disabled", as: :cookies_disabled
|
||||||
get "accountless_user" => 'pages#show', id: "accountless_user", as: :accountless_user
|
get "accountless_user" => 'pages#show', id: "accountless_user", as: :accountless_user
|
||||||
get "nanocosmos_player" => 'pages#show', id: "nanocosmos_player", as: :nanocosmos_player
|
|
||||||
|
|
||||||
resource :session, only: [:new, :create]
|
resource :session, only: [:new, :create]
|
||||||
resources :password_resets, only: [:new, :create, :edit, :update]
|
resources :password_resets, only: [:new, :create, :edit, :update]
|
||||||
|
|||||||
@@ -542,9 +542,9 @@ CREATE TABLE public.broadcast_recordings (
|
|||||||
updated_at timestamp(6) without time zone NOT NULL,
|
updated_at timestamp(6) without time zone NOT NULL,
|
||||||
duration double precision,
|
duration double precision,
|
||||||
hidden boolean DEFAULT false,
|
hidden boolean DEFAULT false,
|
||||||
starred boolean DEFAULT false,
|
|
||||||
name character varying,
|
name character varying,
|
||||||
description text
|
description text,
|
||||||
|
starred boolean DEFAULT false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -1492,6 +1492,7 @@ CREATE TABLE public.settings (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE SEQUENCE public.settings_id_seq
|
CREATE SEQUENCE public.settings_id_seq
|
||||||
|
AS integer
|
||||||
START WITH 1
|
START WITH 1
|
||||||
INCREMENT BY 1
|
INCREMENT BY 1
|
||||||
NO MINVALUE
|
NO MINVALUE
|
||||||
@@ -1527,6 +1528,7 @@ CREATE TABLE public.taggings (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE SEQUENCE public.taggings_id_seq
|
CREATE SEQUENCE public.taggings_id_seq
|
||||||
|
AS integer
|
||||||
START WITH 1
|
START WITH 1
|
||||||
INCREMENT BY 1
|
INCREMENT BY 1
|
||||||
NO MINVALUE
|
NO MINVALUE
|
||||||
@@ -1557,6 +1559,7 @@ CREATE TABLE public.tags (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE SEQUENCE public.tags_id_seq
|
CREATE SEQUENCE public.tags_id_seq
|
||||||
|
AS integer
|
||||||
START WITH 1
|
START WITH 1
|
||||||
INCREMENT BY 1
|
INCREMENT BY 1
|
||||||
NO MINVALUE
|
NO MINVALUE
|
||||||
|
|||||||
@@ -30,16 +30,6 @@ RSpec.describe Api::AcquiredMediaReleasesController, type: :controller do
|
|||||||
|
|
||||||
expect(response).to be_successful
|
expect(response).to be_successful
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'contains files attachment data' do
|
|
||||||
tested_release = create(:acquired_media_release, name: 'ct1', project_id: project.id)
|
|
||||||
|
|
||||||
sign_in_to_api(current_user)
|
|
||||||
get :show, params: { id: tested_release.id }
|
|
||||||
|
|
||||||
expect(response.body).to match /file_infos/
|
|
||||||
expect(response.body).to match /files/
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create' do
|
describe '#create' do
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ RSpec.describe Api::ProfilesController, type: :controller do
|
|||||||
expect(response).to be_successful
|
expect(response).to be_successful
|
||||||
expect(response_body_data).to include('id' => current_user.to_param, 'type' => 'user')
|
expect(response_body_data).to include('id' => current_user.to_param, 'type' => 'user')
|
||||||
expect(response_body_data_attributes).to include('email' => current_user.email)
|
expect(response_body_data_attributes).to include('email' => current_user.email)
|
||||||
expect(response_body_data_attributes).to include('full_name' => current_user.full_name)
|
|
||||||
expect(response_body_data_attributes).to include('company_name' => current_user.primary_account.name)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -386,13 +386,6 @@ RSpec.feature 'User manages contract templates', type: :feature do
|
|||||||
expect(ct.signature_legal_text.id).not_to eq ContractTemplate.last.signature_legal_text.id
|
expect(ct.signature_legal_text.id).not_to eq ContractTemplate.last.signature_legal_text.id
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'trix editor has underline button', js: true do
|
|
||||||
visit new_project_contract_template_path(project)
|
|
||||||
|
|
||||||
select 'Appearance Release', from: 'Release type'
|
|
||||||
expect(page).to have_selector("button[data-trix-attribute='underline']")
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'When the user is associate' do
|
context 'When the user is associate' do
|
||||||
let(:current_user) { create(:user, :associate) }
|
let(:current_user) { create(:user, :associate) }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user