spina-admin-journal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +99 -0
- data/Rakefile +36 -0
- data/app/assets/config/spina_admin_journal_manifest.js +3 -0
- data/app/assets/javascripts/spina/admin/journal/application.es6 +72 -0
- data/app/assets/stylesheets/spina/admin/journal/application.css +27 -0
- data/app/controllers/spina/admin/journal/application_controller.rb +26 -0
- data/app/controllers/spina/admin/journal/articles_controller.rb +125 -0
- data/app/controllers/spina/admin/journal/authors_controller.rb +83 -0
- data/app/controllers/spina/admin/journal/institutions_controller.rb +71 -0
- data/app/controllers/spina/admin/journal/issues_controller.rb +129 -0
- data/app/controllers/spina/admin/journal/journals_controller.rb +73 -0
- data/app/controllers/spina/admin/journal/volumes_controller.rb +79 -0
- data/app/models/spina/admin/journal.rb +11 -0
- data/app/models/spina/admin/journal/affiliation.rb +62 -0
- data/app/models/spina/admin/journal/article.rb +55 -0
- data/app/models/spina/admin/journal/author.rb +47 -0
- data/app/models/spina/admin/journal/authorship.rb +19 -0
- data/app/models/spina/admin/journal/institution.rb +32 -0
- data/app/models/spina/admin/journal/issue.rb +49 -0
- data/app/models/spina/admin/journal/journal.rb +50 -0
- data/app/models/spina/admin/journal/volume.rb +37 -0
- data/app/validators/spina/admin/journal/uri_validator.rb +24 -0
- data/app/views/layouts/spina/admin/journal/articles.html.haml +10 -0
- data/app/views/layouts/spina/admin/journal/authors.html.haml +10 -0
- data/app/views/layouts/spina/admin/journal/institutions.html.haml +10 -0
- data/app/views/layouts/spina/admin/journal/issues.html.haml +10 -0
- data/app/views/layouts/spina/admin/journal/journals.html.haml +10 -0
- data/app/views/layouts/spina/admin/journal/volumes.html.haml +10 -0
- data/app/views/spina/admin/hooks/journal/_head.html.haml +2 -0
- data/app/views/spina/admin/hooks/journal/_primary_navigation.html.haml +27 -0
- data/app/views/spina/admin/hooks/journal/_website_secondary_navigation.html.haml +0 -0
- data/app/views/spina/admin/journal/affiliations/_affiliation.html.haml +8 -0
- data/app/views/spina/admin/journal/application/_empty_list.html.haml +3 -0
- data/app/views/spina/admin/journal/articles/_article.html.haml +10 -0
- data/app/views/spina/admin/journal/articles/_form.html.haml +29 -0
- data/app/views/spina/admin/journal/articles/_form_authors.html.haml +10 -0
- data/app/views/spina/admin/journal/articles/_form_details.html.haml +52 -0
- data/app/views/spina/admin/journal/articles/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/articles/index.html.haml +19 -0
- data/app/views/spina/admin/journal/articles/new.html.haml +1 -0
- data/app/views/spina/admin/journal/authors/_author.html.haml +8 -0
- data/app/views/spina/admin/journal/authors/_form.html.haml +29 -0
- data/app/views/spina/admin/journal/authors/_form_affiliation.html.haml +20 -0
- data/app/views/spina/admin/journal/authors/_form_articles.html.haml +18 -0
- data/app/views/spina/admin/journal/authors/_form_details.html.haml +6 -0
- data/app/views/spina/admin/journal/authors/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/authors/index.html.haml +17 -0
- data/app/views/spina/admin/journal/authors/new.html.haml +1 -0
- data/app/views/spina/admin/journal/institutions/_form.html.haml +29 -0
- data/app/views/spina/admin/journal/institutions/_form_details.html.haml +9 -0
- data/app/views/spina/admin/journal/institutions/_form_view_affiliations.html.haml +10 -0
- data/app/views/spina/admin/journal/institutions/_institution.html.haml +9 -0
- data/app/views/spina/admin/journal/institutions/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/institutions/index.html.haml +16 -0
- data/app/views/spina/admin/journal/institutions/new.html.haml +1 -0
- data/app/views/spina/admin/journal/issues/_form.html.haml +29 -0
- data/app/views/spina/admin/journal/issues/_form_articles.html.haml +14 -0
- data/app/views/spina/admin/journal/issues/_form_details.html.haml +32 -0
- data/app/views/spina/admin/journal/issues/_issue.html.haml +9 -0
- data/app/views/spina/admin/journal/issues/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/issues/index.html.haml +18 -0
- data/app/views/spina/admin/journal/issues/new.html.haml +1 -0
- data/app/views/spina/admin/journal/journals/_form.html.haml +35 -0
- data/app/views/spina/admin/journal/journals/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/journals/index.html.haml +27 -0
- data/app/views/spina/admin/journal/journals/new.html.haml +1 -0
- data/app/views/spina/admin/journal/volumes/_form.html.haml +15 -0
- data/app/views/spina/admin/journal/volumes/_form_details.html.haml +10 -0
- data/app/views/spina/admin/journal/volumes/_form_issues.html.haml +13 -0
- data/app/views/spina/admin/journal/volumes/_volume.html.haml +7 -0
- data/app/views/spina/admin/journal/volumes/edit.html.haml +1 -0
- data/app/views/spina/admin/journal/volumes/index.html.haml +17 -0
- data/app/views/spina/admin/journal/volumes/new.html.haml +1 -0
- data/config/locales/en.yml +184 -0
- data/config/routes.rb +21 -0
- data/db/migrate/20201216152147_create_spina_admin_journal_journals.rb +13 -0
- data/db/migrate/20201216153822_create_spina_admin_journal_volumes.rb +13 -0
- data/db/migrate/20201216155113_create_spina_admin_journal_issues.rb +15 -0
- data/db/migrate/20201216161122_create_spina_admin_journal_articles.rb +16 -0
- data/db/migrate/20201216205633_create_spina_admin_journal_institutions.rb +11 -0
- data/db/migrate/20201216211224_create_spina_admin_journal_authors.rb +7 -0
- data/db/migrate/20201216221146_create_spina_admin_journal_affiliations.rb +15 -0
- data/db/migrate/20201216230816_create_spina_admin_journal_authorships.rb +14 -0
- data/db/migrate/20201231165231_create_spina_admin_journal_parts.rb +12 -0
- data/db/migrate/20210424123450_add_json_attributes_to_spina_admin_journal_journals.rb +7 -0
- data/db/migrate/20210424123521_add_json_attributes_to_spina_admin_journal_issues.rb +7 -0
- data/db/migrate/20210424123555_add_json_attributes_to_spina_admin_journal_articles.rb +7 -0
- data/lib/spina/admin/journal.rb +18 -0
- data/lib/spina/admin/journal/engine.rb +17 -0
- data/lib/spina/admin/journal/version.rb +9 -0
- data/lib/tasks/spina/admin/journal_tasks.rake +5 -0
- data/vendor/assets/javascripts/spina/admin/journal/html5sortable.js +1295 -0
- metadata +388 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 75a11c42a861742be9bee3d10d3a84f745f2d489b8a1ad61bf8e699f4f7fdc04
|
|
4
|
+
data.tar.gz: 343abc141c3af6b35492ec12a4c99325b116a3f63c5058fe7c61359cdfcd0da2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8209f366bfdd31dee8b559a9ca0c3966f3383687560b87a20cda19fbb198eb8faa5929d07e1b97b773464ab950fb5d2c298b4e168a22afacec726c7bb7fee2a4
|
|
7
|
+
data.tar.gz: 7182be875c118c6c59322b6e5a3fd51d81d5d51700be8db549ae48438df05bbb2fd9c290219cdbcae3d28b5530e172e5891ceb1636954c7aa36410406f96573b
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2021 Louis Van Steene
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Spina::Admin::Journal
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://codecov.io/gh/louis-vs/spina-admin-journal)
|
|
5
|
+
[](https://www.codefactor.io/repository/github/louis-vs/spina-admin-journal)
|
|
6
|
+
[](https://lgtm.com/projects/g/louis-vs/spina-admin-journal/alerts/)
|
|
7
|
+
[](https://lgtm.com/projects/g/louis-vs/spina-admin-journal/context:javascript)
|
|
8
|
+
[](http://inch-ci.org/github/louis-vs/spina-admin-journal)
|
|
9
|
+
|
|
10
|
+
*Journal* is a plugin for [Spina](https://www.spinacms.com/), a content management system built in [Ruby on Rails](http://rubyonrails.org/). *Journal* augments Spina by providing an admin interface for managing an academic journal.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
The plugin adds two menus to Spina's primary navigation:
|
|
15
|
+
|
|
16
|
+
* **Journal settings** provides access to global properties of the journal. It is divided into 3 submenus:
|
|
17
|
+
* **Journal** allows you to change the name of the journal.
|
|
18
|
+
* **Institutions** allows you to add institutions, to which authors can be affiliated.
|
|
19
|
+
* **Authors** allows you to add authors, who can then be added to articles.
|
|
20
|
+
* The **journal content** menu will be named after the journal as specified in Journal Settings. It provides a means of editing the content of the journal and is divided into three submenus:
|
|
21
|
+
* **Volumes** allows you to add and remove volumes of the journal, and edit their respective issues.
|
|
22
|
+
* **Issues** allows you to add, edit and remove issues of particular volumes of the journal, and edit their respective articles.
|
|
23
|
+
* **Articles** allows you to add, edit and remove articles belonging to particular issues.
|
|
24
|
+
|
|
25
|
+
The plugin does not provide any public-facing frontend. However, an example implementation can be found at **[TBC]**.
|
|
26
|
+
|
|
27
|
+
**NB this plugin is currently a work in progress**: please wait until an official release to use this plugin in production.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
### From scratch
|
|
32
|
+
|
|
33
|
+
Make sure you have a working installation of Ruby on Rails 6.1. You can find a setup guide [here](https://guides.rubyonrails.org/getting_started.html).
|
|
34
|
+
|
|
35
|
+
Then run:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
$ rails new your-app --database=postgresql
|
|
39
|
+
$ cd your-app
|
|
40
|
+
$ bin/rails db:create
|
|
41
|
+
$ bin/rails active_storage:install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Add this line to your new application's Gemfile:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
gem 'spina', '~> 2.0'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
And then execute:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
$ bundle install
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Run the Spina install generator:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
$ bin/rails g spina:install
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
And follow the prompts. Once this is complete, follow the instructions below.
|
|
63
|
+
|
|
64
|
+
### For existing Spina installations
|
|
65
|
+
|
|
66
|
+
Add this line to your application's Gemfile:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
gem 'spina-admin-journal', '~> 0.1'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
And then execute:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
$ bundle install
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You'll then need to install and run the migrations for the journal:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
$ bin/rails spina_admin_journal_engine:install:migrations
|
|
82
|
+
$ bin/rails db:migrate
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
You can then start a local server to test that everything's working.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
$ bin/rails s
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
You can manually populate the database from within the app, or alternatively you can use seed data for testing. A sample `seeds.rb` file can be found [here](../master/test/dummy/db/seeds.rb).
|
|
92
|
+
|
|
93
|
+
## Contributing
|
|
94
|
+
|
|
95
|
+
Bug reports and feature requests are welcome in the [Issues](https://github.com/louis-vs/spina-admin-journal/issues) section. Translations are also very welcome!
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require 'yard'
|
|
10
|
+
|
|
11
|
+
YARD::Rake::YardocTask.new(:yardoc) do |t|
|
|
12
|
+
t.files = ['lib/**/*.rb', 'app/**/*.rb']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
|
16
|
+
load 'rails/tasks/engine.rake'
|
|
17
|
+
|
|
18
|
+
load 'rails/tasks/statistics.rake'
|
|
19
|
+
|
|
20
|
+
require 'bundler/gem_tasks'
|
|
21
|
+
|
|
22
|
+
require 'rake/testtask'
|
|
23
|
+
|
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
|
25
|
+
t.libs << 'test'
|
|
26
|
+
t.pattern = 'test/**/*_test.rb'
|
|
27
|
+
t.verbose = false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require 'rubocop/rake_task'
|
|
31
|
+
|
|
32
|
+
RuboCop::RakeTask.new do |t|
|
|
33
|
+
t.options << '--parallel' if ENV['CI']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
task default: :test
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//= require spina/admin/journal/html5sortable
|
|
2
|
+
/* global sortable */
|
|
3
|
+
|
|
4
|
+
$(document).on('turbolinks:load', () => {
|
|
5
|
+
// html5sortable configuration
|
|
6
|
+
sortable('.html5sortable', {
|
|
7
|
+
items: 'tr',
|
|
8
|
+
itemSerializer: (serializedItem) => {
|
|
9
|
+
return {
|
|
10
|
+
position: serializedItem.index + 1,
|
|
11
|
+
id: serializedItem.node.getAttribute('data-id')
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
containerSerializer: (serializedContainer) => {
|
|
15
|
+
return {
|
|
16
|
+
name: serializedContainer.node.getAttribute('data-sorted-collection')
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// add sorting event listener if there is a sortable container on the page
|
|
22
|
+
if(typeof sortable('.html5sortable')[0] !== 'undefined') {
|
|
23
|
+
sortable('.html5sortable')[0].addEventListener('sortupdate', e => {
|
|
24
|
+
let container = e.detail.destination.container;
|
|
25
|
+
let serialized = sortable('.html5sortable', 'serialize')[0];
|
|
26
|
+
let data = serialized.items.reduce((map, obj) => {
|
|
27
|
+
map[`${serialized.container.name}[list[${obj.id}]]`] = obj.position;
|
|
28
|
+
return map;
|
|
29
|
+
}, {});
|
|
30
|
+
|
|
31
|
+
let displayError = (...args) => {
|
|
32
|
+
let message = 'An unknown error occured.'; // not translateable (but should never happen)
|
|
33
|
+
if(typeof args[0] === 'string') {
|
|
34
|
+
message = args[0];
|
|
35
|
+
}
|
|
36
|
+
// display error message
|
|
37
|
+
$('.sort-message').html('');
|
|
38
|
+
$('.sort-message').removeClass('animate-fadein success');
|
|
39
|
+
$('.sort-message').width(); // trigger reflow
|
|
40
|
+
$('.sort-message').html(message).addClass('error animate-fadein');
|
|
41
|
+
// TODO: return element to its origin
|
|
42
|
+
// this needs to be done manually, but may not really be necessary since the displayed
|
|
43
|
+
// numbers won't change
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// send sort request
|
|
47
|
+
$.ajax({
|
|
48
|
+
url: $('.html5sortable').eq(0).data('sort-url'),
|
|
49
|
+
type: 'PATCH',
|
|
50
|
+
dataType: 'json',
|
|
51
|
+
data: data,
|
|
52
|
+
success: (data) => {
|
|
53
|
+
if(data.success) {
|
|
54
|
+
// display success message
|
|
55
|
+
$('.sort-message').html(''); // clear message
|
|
56
|
+
$('.sort-message').removeClass('animate-fadein error');
|
|
57
|
+
$('.sort-message').width(); // trigger reflow (for animation to work)
|
|
58
|
+
$('.sort-message').html(data.message).addClass('success animate-fadein');
|
|
59
|
+
// update displayed position number
|
|
60
|
+
// NB this is done entirely clientside, so there is the potential for desync
|
|
61
|
+
for(let i = 0; i < container.children.length; i++) {
|
|
62
|
+
container.children[i].getElementsByClassName('position-display')[0].innerHTML = (i+1).toString();
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
displayError(data.message);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
error: displayError
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* Completely overkill animated message for successful sorting */
|
|
2
|
+
.sort-message {
|
|
3
|
+
padding-top: 10px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.sort-message.success {
|
|
7
|
+
color: green;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.sort-message.error {
|
|
11
|
+
color: red;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.animate-fadein {
|
|
15
|
+
animation-name: fadein;
|
|
16
|
+
animation-duration: 500ms;
|
|
17
|
+
animation-timing-function: ease-out;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@keyframes fadein {
|
|
21
|
+
from {
|
|
22
|
+
opacity: 0.1;
|
|
23
|
+
}
|
|
24
|
+
to {
|
|
25
|
+
opacity: 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Journal
|
|
6
|
+
# Custom controller for journal plugin. Sets the layout and adds a flash type.
|
|
7
|
+
class ApplicationController < AdminController
|
|
8
|
+
add_flash_types :success
|
|
9
|
+
|
|
10
|
+
layout :admin_layout, only: %i[new edit]
|
|
11
|
+
|
|
12
|
+
before_action :set_locale
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def admin_layout
|
|
17
|
+
'spina/admin/admin'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def set_locale
|
|
21
|
+
@locale = params[:locale] || I18n.default_locale
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Journal
|
|
6
|
+
# Controller for {Article} records.
|
|
7
|
+
class ArticlesController < ApplicationController
|
|
8
|
+
PARTS_PARAMS = [
|
|
9
|
+
:name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id,
|
|
10
|
+
{ images_attributes: %i[filename signed_blob_id image_id alt],
|
|
11
|
+
content_attributes: [
|
|
12
|
+
:name, :title,
|
|
13
|
+
{ parts_attributes: [
|
|
14
|
+
:name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id,
|
|
15
|
+
{ images_attributes: %i[filename signed_blob_id image_id alt] }
|
|
16
|
+
] }
|
|
17
|
+
] }
|
|
18
|
+
].freeze
|
|
19
|
+
CONTENT_PARAMS = Spina.config.locales.inject({}) do |params, locale|
|
|
20
|
+
params.merge("#{locale}_content_attributes": [*PARTS_PARAMS])
|
|
21
|
+
end
|
|
22
|
+
PARAMS = [:issue_id, :title, :url, :doi, { affiliation_ids: [], **CONTENT_PARAMS }].freeze
|
|
23
|
+
PARTS = %w[abstract attachment].freeze
|
|
24
|
+
|
|
25
|
+
before_action :set_breadcrumb
|
|
26
|
+
before_action :set_tabs, except: %i[index destroy sort]
|
|
27
|
+
before_action :set_article, only: %i[edit update destroy]
|
|
28
|
+
before_action :set_parts_attributes, only: %i[new edit]
|
|
29
|
+
before_action :build_parts, only: %i[edit]
|
|
30
|
+
|
|
31
|
+
def index
|
|
32
|
+
@articles = Article.sorted_desc
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def new
|
|
36
|
+
@article = Article.new
|
|
37
|
+
build_parts
|
|
38
|
+
add_breadcrumb t('.new')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def edit; end
|
|
42
|
+
|
|
43
|
+
def create
|
|
44
|
+
@article = Article.new(article_params)
|
|
45
|
+
sister_articles = Article.where(issue: @article.issue_id)
|
|
46
|
+
@article.number = sister_articles.any? ? sister_articles.sorted_desc.first.number + 1 : 1
|
|
47
|
+
|
|
48
|
+
if @article.save
|
|
49
|
+
redirect_to admin_journal_articles_path, success: t('.saved')
|
|
50
|
+
else
|
|
51
|
+
render :new
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def update
|
|
56
|
+
if @article.update(article_params)
|
|
57
|
+
redirect_to admin_journal_articles_path, success: t('.saved')
|
|
58
|
+
else
|
|
59
|
+
render :edit
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def destroy
|
|
64
|
+
@article.destroy
|
|
65
|
+
respond_to do |format|
|
|
66
|
+
format.html do
|
|
67
|
+
redirect_to admin_journal_articles_path, success: t('.deleted')
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def sort
|
|
73
|
+
ActiveRecord::Base.transaction do
|
|
74
|
+
sort_params.each do |id, new_pos|
|
|
75
|
+
Article.find(id.to_i).update_attribute(:number, new_pos.to_i) # rubocop:disable Rails/SkipsModelValidations
|
|
76
|
+
end
|
|
77
|
+
validate_sort_order
|
|
78
|
+
end
|
|
79
|
+
render json: { success: true, message: t('.sort_success') }
|
|
80
|
+
rescue ActiveRecord::RecordInvalid
|
|
81
|
+
render json: { success: false, message: t('.sort_error') }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def article_params
|
|
87
|
+
params.require(:admin_journal_article).permit(PARAMS)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def sort_params
|
|
91
|
+
params.require(:admin_journal_articles).require(:list).permit!
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def validate_sort_order
|
|
95
|
+
Article.where(issue_id: params[:issue_id]).each do |article|
|
|
96
|
+
raise ActiveRecord::RecordInvalid if article.invalid?
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def set_breadcrumb
|
|
101
|
+
add_breadcrumb Article.model_name.human(count: :many), admin_journal_articles_path
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_tabs
|
|
105
|
+
@tabs = %w[details authors]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def set_article
|
|
109
|
+
@article = Article.find(params[:id])
|
|
110
|
+
add_breadcrumb @article.title
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def set_parts_attributes
|
|
114
|
+
@parts_attributes = current_theme.parts.select { |part| PARTS.include? part[:name] }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def build_parts
|
|
118
|
+
return unless @parts_attributes.is_a? Array
|
|
119
|
+
|
|
120
|
+
@parts = @parts_attributes.collect { |part_attributes| @article.part(part_attributes) }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spina
|
|
4
|
+
module Admin
|
|
5
|
+
module Journal
|
|
6
|
+
# Controller for {Author} records and their corresponding {Affiliation}s.
|
|
7
|
+
class AuthorsController < ApplicationController
|
|
8
|
+
before_action :set_breadcrumb
|
|
9
|
+
before_action :set_tabs, except: %i[index destroy]
|
|
10
|
+
before_action :set_author, only: %i[edit update destroy]
|
|
11
|
+
|
|
12
|
+
def index
|
|
13
|
+
@authors = Author.all
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def new
|
|
17
|
+
@author = Author.new
|
|
18
|
+
@author.affiliations << Affiliation.new(status: :primary)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def edit; end
|
|
22
|
+
|
|
23
|
+
def create
|
|
24
|
+
@author = Author.new(modified_params)
|
|
25
|
+
if @author.save
|
|
26
|
+
redirect_to admin_journal_authors_path, success: t('.saved')
|
|
27
|
+
else
|
|
28
|
+
render :new
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def update
|
|
33
|
+
if @author.update(modified_params)
|
|
34
|
+
redirect_to admin_journal_authors_path, success: t('.saved')
|
|
35
|
+
else
|
|
36
|
+
render :edit
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def destroy
|
|
41
|
+
@author.destroy
|
|
42
|
+
respond_to do |format|
|
|
43
|
+
format.html do
|
|
44
|
+
redirect_to admin_journal_authors_path, success: t('.deleted')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def author_params
|
|
52
|
+
params.require(:admin_journal_author).permit(:primary_affiliation_index,
|
|
53
|
+
affiliations_attributes: %i[id institution_id first_name
|
|
54
|
+
surname])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def modified_params
|
|
58
|
+
primary_affiliation_index = params[:admin_journal_author][:primary_affiliation_index]
|
|
59
|
+
new_params = author_params.except :primary_affiliation_index
|
|
60
|
+
unless new_params[:affiliations_attributes].nil? || primary_affiliation_index.nil?
|
|
61
|
+
new_params[:affiliations_attributes].each_key do |index|
|
|
62
|
+
new_params[:affiliations_attributes][index][:status] = index == primary_affiliation_index ? 'primary' : 'other' # rubocop:disable Layout/LineLength
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
new_params
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def set_breadcrumb
|
|
69
|
+
add_breadcrumb Author.model_name.human(count: :many), admin_journal_authors_path
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def set_tabs
|
|
73
|
+
@tabs = %w[details articles]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def set_author
|
|
77
|
+
@author = Author.find(params[:id])
|
|
78
|
+
add_breadcrumb @author.primary_affiliation.name
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|