neurolibre 1.5.3
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/CHANGELOG.md +104 -0
- data/LICENSE +21 -0
- data/README.md +5 -0
- data/lib/neurolibre.rb +14 -0
- data/lib/theoj/author.rb +107 -0
- data/lib/theoj/git.rb +21 -0
- data/lib/theoj/github.rb +63 -0
- data/lib/theoj/journal.rb +81 -0
- data/lib/theoj/journals_data.rb +66 -0
- data/lib/theoj/orcid.rb +96 -0
- data/lib/theoj/paper.rb +161 -0
- data/lib/theoj/published_paper.rb +46 -0
- data/lib/theoj/review_issue.rb +92 -0
- data/lib/theoj/submission.rb +233 -0
- data/lib/theoj/version.rb +3 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 61b64abbb7fd96d5b841b156ff5872972ba51b2c7765c2f32b08c2894ac39917
|
4
|
+
data.tar.gz: 011d818ffd6862603ab817e359cedcd344c1c6263703cac5004f1ca8339a8003
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff5f5745c38a93662bca47cf623671c34b4784217270762a66a3b489082feadc072f94996c954b1d20bd8e52571355feeade515811315cdaccd75e77c2157cb4
|
7
|
+
data.tar.gz: 777020c7718448df0b583fc5dc82e7cc3df8ad3b5e699853328a92bd4c946dd7f998b0dc20db903f82346d587c243b546ee02a38bf33453de9632024085b2a08
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 1.5.2 (2022-10-29)
|
4
|
+
|
5
|
+
- Updated journal data for JuliaCon
|
6
|
+
|
7
|
+
## 1.5.1 (2022-10-25)
|
8
|
+
|
9
|
+
- Remove newlines from paper's title
|
10
|
+
- Faraday and Octokit dependencies updated to latest major versions
|
11
|
+
|
12
|
+
## 1.5.0 (2022-10-02)
|
13
|
+
|
14
|
+
- Added Commonmarker as dependency
|
15
|
+
- Submission metadata's title is converted to plain text
|
16
|
+
|
17
|
+
## 1.4.1 (2022-09-28)
|
18
|
+
|
19
|
+
- Added method to Submission to get track information
|
20
|
+
|
21
|
+
## 1.4.0 (2022-08-01)
|
22
|
+
|
23
|
+
- Added method to Journal to get year/volume/issue information for any date
|
24
|
+
- Submission metadata now takes into account published paper status
|
25
|
+
|
26
|
+
## 1.3.6 (2022-07-11)
|
27
|
+
|
28
|
+
- Improve parsing of author names
|
29
|
+
|
30
|
+
## 1.3.5 (2022-07-01)
|
31
|
+
|
32
|
+
- Added configuration for JuliaCon
|
33
|
+
|
34
|
+
## 1.3.4 (2022-05-29)
|
35
|
+
|
36
|
+
- Use Faraday v2 (updated Octokit and other dependencies)
|
37
|
+
|
38
|
+
## 1.3.3 (2022-03-31)
|
39
|
+
|
40
|
+
- Fix bug with upcased user logins
|
41
|
+
|
42
|
+
## 1.3.2 (2022-03-17)
|
43
|
+
|
44
|
+
- Allow setting GitHub access using GITHUB_TOKEN env var
|
45
|
+
|
46
|
+
## 1.3.1 (2022-03-09)
|
47
|
+
|
48
|
+
- Fix error when loading metadata for papers with wrong path
|
49
|
+
|
50
|
+
## 1.3.0 (2022-03-02)
|
51
|
+
|
52
|
+
- Change branches using git-switch instead of git-checkout to remove ambiguaties. Requires Git >= 2.23
|
53
|
+
|
54
|
+
## 1.2.1 (2021-11-30)
|
55
|
+
|
56
|
+
- Changed metadata dates format to ISO
|
57
|
+
- Changed editor and reviewers metadata values to github login
|
58
|
+
- Removed languages from article metadata
|
59
|
+
|
60
|
+
## 1.2.0 (2021-11-23)
|
61
|
+
|
62
|
+
- Added reviews_repository_url to Journal
|
63
|
+
- Added article_metadata to Submission
|
64
|
+
- Added editor and paper dates lookup information in Submission
|
65
|
+
- Fixed error reading reviewers list from issue body
|
66
|
+
|
67
|
+
## 1.1.1 (2021-11-05)
|
68
|
+
|
69
|
+
- Added support for test-journal
|
70
|
+
|
71
|
+
## 1.1.0 (2021-10-29)
|
72
|
+
|
73
|
+
- Added Theoj::PublishedPaper object with metadata from Journal's API
|
74
|
+
- Added custom Error class
|
75
|
+
|
76
|
+
## 1.0.0 (2021-10-20)
|
77
|
+
|
78
|
+
- Added method to Journal to create paper_id from issue_id
|
79
|
+
- Added method to Journal to get a DOI based on a paper id
|
80
|
+
- Added languages to Paper
|
81
|
+
- Added authors info to Paper
|
82
|
+
- Author object
|
83
|
+
- Added ORCID validation
|
84
|
+
- Added Submission object, grouping a paper, a review issue and a journal
|
85
|
+
- Added paper depositing
|
86
|
+
|
87
|
+
## 0.0.3 (2021-10-08)
|
88
|
+
|
89
|
+
- Added metadata methods to Paper
|
90
|
+
- Added to ReviewIssue: editor, reviewers, archive, version
|
91
|
+
- New method to read any value from review's issue body
|
92
|
+
- Values read from issue boy will be empty if Pending or TBD
|
93
|
+
- Added journal config data for OpenJournals: JOSS and JOSE
|
94
|
+
|
95
|
+
|
96
|
+
## 0.0.2 (2021-09-22)
|
97
|
+
|
98
|
+
- Available objects: Theoj::Journal, Theoj::ReviewIssue and Theoj::Paper
|
99
|
+
|
100
|
+
|
101
|
+
## 0.0.1 (2021-09-22)
|
102
|
+
|
103
|
+
- Gem created
|
104
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Juanjo Bazán
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
# The Open Journal
|
2
|
+
A library to manage editorial objects used by the open journals review process
|
3
|
+
|
4
|
+
[](https://github.com/xuanxu/theoj/actions/workflows/ci.yml)
|
5
|
+
[](https://badge.fury.io/rb/theoj)
|
data/lib/neurolibre.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "theoj/version"
|
2
|
+
require_relative "theoj/git"
|
3
|
+
require_relative "theoj/github"
|
4
|
+
require_relative "theoj/orcid"
|
5
|
+
require_relative "theoj/published_paper"
|
6
|
+
require_relative "theoj/submission"
|
7
|
+
require_relative "theoj/journal"
|
8
|
+
require_relative "theoj/review_issue"
|
9
|
+
require_relative "theoj/paper"
|
10
|
+
require_relative "theoj/author"
|
11
|
+
|
12
|
+
module Theoj
|
13
|
+
class Error < StandardError; end
|
14
|
+
end
|
data/lib/theoj/author.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require "nameable"
|
2
|
+
|
3
|
+
module Theoj
|
4
|
+
class Author
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :orcid
|
7
|
+
attr_accessor :affiliation
|
8
|
+
|
9
|
+
AUTHOR_FOOTNOTE_REGEX = /^[^\^]*/
|
10
|
+
|
11
|
+
# Initialized with authors & affiliations block in the YAML header from an Open Journal paper
|
12
|
+
# e.g. https://joss.readthedocs.io/en/latest/submitting.html#example-paper-and-bibliography
|
13
|
+
def initialize(name, orcid, index, affiliations_hash)
|
14
|
+
parse_name name
|
15
|
+
@orcid = validate_orcid orcid
|
16
|
+
@affiliation = build_affiliation_string(index, affiliations_hash)
|
17
|
+
end
|
18
|
+
|
19
|
+
def given_name
|
20
|
+
@parsed_name.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def middle_name
|
24
|
+
@parsed_name.middle
|
25
|
+
end
|
26
|
+
|
27
|
+
def last_name
|
28
|
+
@parsed_name.last
|
29
|
+
end
|
30
|
+
|
31
|
+
def initials
|
32
|
+
[@parsed_name.first, @parsed_name.middle].compact.map {|v| v[0] + "."} * ' '
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_h
|
36
|
+
{
|
37
|
+
given_name: given_name,
|
38
|
+
middle_name: middle_name,
|
39
|
+
last_name: last_name,
|
40
|
+
orcid: orcid,
|
41
|
+
affiliation: affiliation
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def parse_name(author_name)
|
48
|
+
if author_name.is_a? Hash
|
49
|
+
g = author_name["given-names"] || author_name["given"] || author_name["first"] || author_name["firstname"]
|
50
|
+
m = author_name["dropping-particle"]
|
51
|
+
s = author_name["surname"] || author_name["family"]
|
52
|
+
|
53
|
+
g = strip_footnotes(g) unless g.nil?
|
54
|
+
s = strip_footnotes(s) unless s.nil?
|
55
|
+
|
56
|
+
@parsed_name = m.nil? ? Nameable::Latin.new(g, s) : Nameable::Latin.new(g, m, s)
|
57
|
+
else
|
58
|
+
@parsed_name = Nameable::Latin.new.parse(strip_footnotes(author_name))
|
59
|
+
end
|
60
|
+
|
61
|
+
@name = @parsed_name.to_nameable
|
62
|
+
end
|
63
|
+
|
64
|
+
# Input: Arfon Smith^[Corresponding author: arfon@example.com]
|
65
|
+
# Output: Arfon Smith
|
66
|
+
def strip_footnotes(author_name)
|
67
|
+
author_name.to_s[AUTHOR_FOOTNOTE_REGEX]
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_orcid(author_orcid)
|
71
|
+
return nil if author_orcid.to_s.strip.empty?
|
72
|
+
|
73
|
+
validator = Theoj::Orcid.new(author_orcid)
|
74
|
+
if validator.valid?
|
75
|
+
return author_orcid.strip
|
76
|
+
else
|
77
|
+
raise Theoj::Error, "Problem with ORCID (#{author_orcid}) for #{self.name}. #{validator.error}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Takes the author affiliation index and a hash of all affiliations and
|
82
|
+
# associates them. Then builds the author affiliation string
|
83
|
+
def build_affiliation_string(index, affiliations_hash)
|
84
|
+
return nil if index.nil? # Some authors don't have an affiliation
|
85
|
+
|
86
|
+
# If multiple affiliations, parse each one and build the affiliation string
|
87
|
+
author_affiliations = []
|
88
|
+
|
89
|
+
# Turn YAML keys into strings so that mixed integer and string affiliations work
|
90
|
+
affiliations_hash.transform_keys!(&:to_s)
|
91
|
+
|
92
|
+
affiliations = index.to_s.split(',').map(&:strip)
|
93
|
+
|
94
|
+
# Raise if we can't parse the string, might be because of this bug :-(
|
95
|
+
# https://bugs.ruby-lang.org/issues/12451
|
96
|
+
affiliations.each do |a|
|
97
|
+
raise Theoj::Error, "Problem with affiliations for #{self.name}, perhaps the " +
|
98
|
+
"affiliations index need quoting?" unless affiliations_hash.has_key?(a)
|
99
|
+
|
100
|
+
author_affiliations << affiliations_hash[a].strip
|
101
|
+
end
|
102
|
+
|
103
|
+
author_affiliations.join(', ')
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
data/lib/theoj/git.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module Theoj
|
5
|
+
module Git
|
6
|
+
def clone_repo(url, local_path)
|
7
|
+
url = URI.extract(url.to_s).first
|
8
|
+
return false if url.nil?
|
9
|
+
|
10
|
+
FileUtils.mkdir_p(local_path)
|
11
|
+
stdout, stderr, status = Open3.capture3 "git clone #{url} #{local_path}"
|
12
|
+
status.success?
|
13
|
+
end
|
14
|
+
|
15
|
+
def change_branch(branch, local_path)
|
16
|
+
return true if (branch.nil? || branch.strip.empty?)
|
17
|
+
stdout, stderr, status = Open3.capture3 "git -C #{local_path} switch #{branch}"
|
18
|
+
status.success?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/theoj/github.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require "octokit"
|
2
|
+
|
3
|
+
# This module includes all the methods involving calls to the GitHub API
|
4
|
+
# It reuses a memoized Octokit::Client instance
|
5
|
+
module Theoj
|
6
|
+
module GitHub
|
7
|
+
|
8
|
+
# Authenticated Octokit
|
9
|
+
def github_client
|
10
|
+
@github_client ||= Octokit::Client.new(access_token: github_access_token, auto_paginate: true)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GitHub access token
|
14
|
+
def github_access_token
|
15
|
+
@github_access_token ||= (ENV["GH_ACCESS_TOKEN"] || ENV["GITHUB_TOKEN"])
|
16
|
+
end
|
17
|
+
|
18
|
+
# GitHub API headers
|
19
|
+
def github_headers
|
20
|
+
@github_headers ||= { "Authorization" => "token #{github_access_token}",
|
21
|
+
"Content-Type" => "application/json",
|
22
|
+
"Accept" => "application/vnd.github.v3+json" }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return an Octokit GitHub Issue
|
26
|
+
def issue(repo, issue_id)
|
27
|
+
@issue ||= github_client.issue(repo, issue_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
# List labels of a GitHub issue
|
31
|
+
def issue_labels(repo, issue_id)
|
32
|
+
github_client.labels_for_issue(repo, issue_id).map { |l| l[:name] }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Uses the GitHub API to determine if a user is already a collaborator of the repo
|
36
|
+
def is_collaborator?(repo, username)
|
37
|
+
username = user_login(username)
|
38
|
+
github_client.collaborator?(repo, username)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Uses the GitHub API to determine if a user is already a collaborator of the repo
|
42
|
+
def can_be_assignee?(repo, username)
|
43
|
+
username = user_login(username)
|
44
|
+
github_client.check_assignee(repo, username)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Uses the GitHub API to determine if a user has a pending invitation
|
48
|
+
def is_invited?(repo, username)
|
49
|
+
username = user_login(username).downcase
|
50
|
+
github_client.repository_invitations(repo).any? { |i| i.invitee.login.downcase == username }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the user login (removes the @ from the username)
|
54
|
+
def user_login(username)
|
55
|
+
username.to_s.strip.sub(/^@/, "")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns true if the string is a valid GitHub isername (starts with @)
|
59
|
+
def username?(username)
|
60
|
+
username.match?(/\A@/)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative "journals_data"
|
2
|
+
|
3
|
+
module Theoj
|
4
|
+
class Journal
|
5
|
+
attr_accessor :data
|
6
|
+
attr_accessor :doi_prefix
|
7
|
+
attr_accessor :url
|
8
|
+
attr_accessor :name
|
9
|
+
attr_accessor :alias
|
10
|
+
attr_accessor :launch_date
|
11
|
+
|
12
|
+
def initialize(custom_data = {})
|
13
|
+
set_data custom_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_year
|
17
|
+
data[:current_year] || Time.new.year
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_volume
|
21
|
+
data[:current_volume] || (Time.new.year - (launch_year - 1))
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_issue
|
25
|
+
data[:current_issue] || (1 + ((Time.new.year * 12 + Time.new.month) - (launch_year * 12 + launch_month)))
|
26
|
+
end
|
27
|
+
|
28
|
+
def paper_id_from_issue(review_issue_id)
|
29
|
+
id = "%05d" % review_issue_id
|
30
|
+
"#{@alias}.#{id}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def paper_doi_for_id(paper_id)
|
34
|
+
"#@doi_prefix/#{paper_id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def reviews_repository_url(issue_id=nil)
|
38
|
+
reviews_url = "https://github.com/#{data[:reviews_repository]}"
|
39
|
+
if issue_id
|
40
|
+
reviews_url += "/issues/" + issue_id.to_s
|
41
|
+
end
|
42
|
+
reviews_url
|
43
|
+
end
|
44
|
+
|
45
|
+
def year_volume_issue_for_date(d)
|
46
|
+
d = Date.parse(d) if d.is_a? String
|
47
|
+
year = d.year
|
48
|
+
volume = year - (launch_year - 1)
|
49
|
+
issue = (1 + ((year * 12 + d.month) - (launch_year * 12 + launch_month)))
|
50
|
+
|
51
|
+
[year, volume, issue]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def set_data(custom_data)
|
57
|
+
@data = default_data.merge(custom_data)
|
58
|
+
@doi_prefix = data[:doi_prefix]
|
59
|
+
@url = data[:url]
|
60
|
+
@name = data[:name]
|
61
|
+
@alias = data[:alias]
|
62
|
+
@launch_date = data[:launch_date]
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_data
|
66
|
+
Theoj::JOURNALS_DATA[:neurolibre]
|
67
|
+
end
|
68
|
+
|
69
|
+
def parsed_launch_date
|
70
|
+
@parsed_launch_date ||= Time.parse(data[:launch_date])
|
71
|
+
end
|
72
|
+
|
73
|
+
def launch_year
|
74
|
+
parsed_launch_date.year
|
75
|
+
end
|
76
|
+
|
77
|
+
def launch_month
|
78
|
+
parsed_launch_date.month
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
module Theoj
|
4
|
+
JOURNALS_DATA = {
|
5
|
+
joss: {
|
6
|
+
doi_prefix: "10.21105",
|
7
|
+
url: "https://joss.theoj.org",
|
8
|
+
name: "Journal of Open Source Software",
|
9
|
+
alias: "joss",
|
10
|
+
launch_date: "2016-05-05",
|
11
|
+
papers_repository: "openjournals/joss-papers",
|
12
|
+
reviews_repository: "openjournals/joss-reviews",
|
13
|
+
deposit_url: "https://joss.theoj.org/papers/api_deposit"
|
14
|
+
},
|
15
|
+
jose: {
|
16
|
+
doi_prefix: "10.21105",
|
17
|
+
url: "https://jose.theoj.org",
|
18
|
+
name: "Journal of Open Source Education",
|
19
|
+
alias: "jose",
|
20
|
+
launch_date: "2018-03-07",
|
21
|
+
papers_repository: "openjournals/jose-papers",
|
22
|
+
reviews_repository: "openjournals/jose-reviews",
|
23
|
+
deposit_url: "https://joss.theoj.org/papers/api_deposit"
|
24
|
+
},
|
25
|
+
jcon: {
|
26
|
+
doi_prefix: "10.21105",
|
27
|
+
url: "https://proceedings.juliacon.org/",
|
28
|
+
name: "The Proceedings of the JuliaCon Conferences",
|
29
|
+
alias: "jcon",
|
30
|
+
launch_date: "2019-07-21",
|
31
|
+
papers_repository: "JuliaCon/proceedings-papers",
|
32
|
+
reviews_repository: "JuliaCon/proceedings-review",
|
33
|
+
deposit_url: "https://proceedings.juliacon.org/papers/api_deposit"
|
34
|
+
},
|
35
|
+
resciencec: {
|
36
|
+
doi_prefix: "10.21105",
|
37
|
+
url: "https://resciencec.theoj.org",
|
38
|
+
name: "ReScience C",
|
39
|
+
alias: "resciencec",
|
40
|
+
launch_date: "2015-05-23",
|
41
|
+
papers_repository: "ReScience/ReScienceC-papers",
|
42
|
+
reviews_repository: "ReScience/ReScienceC-reviews",
|
43
|
+
deposit_url: "https://resciencec.theoj.org/papers/api_deposit"
|
44
|
+
},
|
45
|
+
neurolibre: {
|
46
|
+
doi_prefix: "10.55458",
|
47
|
+
url: "https://neurolibre.org/",
|
48
|
+
name: "NeuroLibre",
|
49
|
+
alias: "neurolibre",
|
50
|
+
launch_date: "2021-01-01",
|
51
|
+
papers_repository: "neurolibre/preprints",
|
52
|
+
reviews_repository: "neurolibre/neurolibre-reviews",
|
53
|
+
deposit_url: "https://neurolibre-neo.herokuapp.com/papers/api_deposit"
|
54
|
+
},
|
55
|
+
test_journal: {
|
56
|
+
doi_prefix: "10.55458",
|
57
|
+
url: "https://staging.neurolibre.org/",
|
58
|
+
name: "NeuroLibre",
|
59
|
+
alias: "neurolibre",
|
60
|
+
launch_date: "2021-01-01",
|
61
|
+
papers_repository: "neurolibre/neurolibre-preprints-testing",
|
62
|
+
reviews_repository: "openjournals/joss-reviews-testing",
|
63
|
+
deposit_url: "https://staging.neurolibre.org/papers/api_deposit"
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
data/lib/theoj/orcid.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
module Theoj
|
2
|
+
class Orcid
|
3
|
+
attr_reader :orcid, :error
|
4
|
+
|
5
|
+
def initialize(orcid)
|
6
|
+
@orcid = orcid.strip
|
7
|
+
@error = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?
|
11
|
+
@error = nil
|
12
|
+
return false unless check_structure
|
13
|
+
return false unless check_length
|
14
|
+
return false unless check_chars
|
15
|
+
|
16
|
+
return false unless correct_checksum?
|
17
|
+
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def packed_orcid
|
22
|
+
orcid.gsub('-', '')
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Returns the last character of the string
|
28
|
+
def checksum_char
|
29
|
+
packed_orcid[-1]
|
30
|
+
end
|
31
|
+
|
32
|
+
def first_11
|
33
|
+
packed_orcid.chop
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_structure
|
37
|
+
groups = orcid.split('-')
|
38
|
+
if groups.size == 4
|
39
|
+
return true
|
40
|
+
else
|
41
|
+
@error = "ORCID looks malformed"
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_length
|
47
|
+
if packed_orcid.length == 16
|
48
|
+
return true
|
49
|
+
else
|
50
|
+
@error = "ORCID looks to be the wrong length"
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_chars
|
56
|
+
valid = true
|
57
|
+
first_11.each_char do |c|
|
58
|
+
if !numeric?(c)
|
59
|
+
@error = "Invalid ORCID digit (#{c})"
|
60
|
+
valid = false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
return valid
|
65
|
+
end
|
66
|
+
|
67
|
+
def correct_checksum?
|
68
|
+
validate_against = checksum_char.to_i
|
69
|
+
validate_against = 10 if (checksum_char == "X" || checksum_char == "x")
|
70
|
+
|
71
|
+
if checksum == validate_against
|
72
|
+
return true
|
73
|
+
else
|
74
|
+
@error = "Invalid ORCID"
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# https://support.orcid.org/knowledgebase/articles/116780-structure-of-the-orcid-identifier
|
80
|
+
def checksum
|
81
|
+
total = 0
|
82
|
+
first_11.each_char do |c|
|
83
|
+
total = (total + c.to_i) * 2
|
84
|
+
end
|
85
|
+
|
86
|
+
remainder = total % 11
|
87
|
+
result = (12 - remainder) % 11
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def numeric?(s)
|
92
|
+
Float(s) != nil rescue false
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
data/lib/theoj/paper.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require "find"
|
2
|
+
require "yaml"
|
3
|
+
require "rugged"
|
4
|
+
require "linguist"
|
5
|
+
|
6
|
+
module Theoj
|
7
|
+
class Paper
|
8
|
+
include Theoj::Git
|
9
|
+
|
10
|
+
attr_accessor :review_issue
|
11
|
+
attr_accessor :repository
|
12
|
+
attr_accessor :paper_path
|
13
|
+
attr_accessor :branch
|
14
|
+
attr_accessor :paper_metadata
|
15
|
+
|
16
|
+
def initialize(repository_url, branch, path = nil)
|
17
|
+
@repository = repository_url
|
18
|
+
@branch = branch
|
19
|
+
find_paper path
|
20
|
+
load_metadata
|
21
|
+
end
|
22
|
+
|
23
|
+
def authors
|
24
|
+
@authors ||= parse_authors
|
25
|
+
end
|
26
|
+
|
27
|
+
def citation_author
|
28
|
+
surname = authors.first.last_name
|
29
|
+
initials = authors.first.initials
|
30
|
+
|
31
|
+
if authors.size > 1
|
32
|
+
return "#{surname} et al."
|
33
|
+
else
|
34
|
+
return "#{surname}, #{initials}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def title
|
39
|
+
@paper_metadata["title"]
|
40
|
+
end
|
41
|
+
|
42
|
+
def tags
|
43
|
+
@paper_metadata["tags"]
|
44
|
+
end
|
45
|
+
|
46
|
+
def date
|
47
|
+
@paper_metadata["date"]
|
48
|
+
end
|
49
|
+
|
50
|
+
def languages
|
51
|
+
@languages ||= detect_languages
|
52
|
+
end
|
53
|
+
|
54
|
+
def bibliography_path
|
55
|
+
@paper_metadata["bibliography"]
|
56
|
+
end
|
57
|
+
|
58
|
+
def local_path
|
59
|
+
@local_path ||= "tmp/#{SecureRandom.hex}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def cleanup
|
63
|
+
FileUtils.rm_rf(local_path) if Dir.exist?(local_path)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.find_paper_path(search_path)
|
67
|
+
paper_path = nil
|
68
|
+
|
69
|
+
if Dir.exist? search_path
|
70
|
+
Find.find(search_path).each do |path|
|
71
|
+
if path =~ /paper\.tex$|paper\.md$/
|
72
|
+
paper_path = path
|
73
|
+
break
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
paper_path
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.from_repo(repository_url, branch = "")
|
82
|
+
Paper.new(repository_url, branch, nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def find_paper(path)
|
88
|
+
if path.to_s.strip.empty?
|
89
|
+
setup_local_repo
|
90
|
+
@paper_path = Theoj::Paper.find_paper_path(local_path)
|
91
|
+
else
|
92
|
+
@paper_path = path
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def setup_local_repo
|
97
|
+
msg_no_repo = "Downloading of the repository failed. Please make sure the URL is correct."
|
98
|
+
msg_no_branch = "Couldn't check the bibtex because branch name is incorrect: #{branch.to_s}"
|
99
|
+
|
100
|
+
error = clone_repo(repository, local_path) ? nil : msg_no_repo
|
101
|
+
(error = change_branch(branch, local_path) ? nil : msg_no_branch) unless error
|
102
|
+
|
103
|
+
failure(error) if error
|
104
|
+
error.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
def load_metadata
|
108
|
+
@paper_metadata ||= if paper_path.nil?
|
109
|
+
{}
|
110
|
+
elsif paper_path.include?('.tex')
|
111
|
+
YAML.load_file(paper_path.gsub('.tex', '.yml'))
|
112
|
+
else
|
113
|
+
YAML.load_file(paper_path)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_authors
|
118
|
+
parsed_authors = []
|
119
|
+
authors_metadata = @paper_metadata['authors']
|
120
|
+
affiliations_metadata = parse_affiliations(@paper_metadata['affiliations'])
|
121
|
+
|
122
|
+
# Loop through the authors block and build up the affiliation
|
123
|
+
authors_metadata.each do |author|
|
124
|
+
author['name'] = author.dup if author['name'].nil?
|
125
|
+
affiliation_index = author['affiliation']
|
126
|
+
failure "Author (#{author['name']}) is missing affiliation" if affiliation_index.nil?
|
127
|
+
begin
|
128
|
+
parsed_author = Author.new(author['name'], author['orcid'], affiliation_index, affiliations_metadata)
|
129
|
+
rescue Exception => e
|
130
|
+
failure(e.message)
|
131
|
+
end
|
132
|
+
parsed_authors << parsed_author
|
133
|
+
end
|
134
|
+
|
135
|
+
parsed_authors
|
136
|
+
end
|
137
|
+
|
138
|
+
def parse_affiliations(affiliations_yaml)
|
139
|
+
affiliations_metadata = {}
|
140
|
+
|
141
|
+
affiliations_yaml.each do |affiliation|
|
142
|
+
affiliations_metadata[affiliation['index']] = affiliation['name']
|
143
|
+
end
|
144
|
+
|
145
|
+
affiliations_metadata
|
146
|
+
end
|
147
|
+
|
148
|
+
def detect_languages
|
149
|
+
repo = Rugged::Repository.discover(paper_path)
|
150
|
+
project = Linguist::Repository.new(repo, repo.head.target_id)
|
151
|
+
|
152
|
+
# Take top five languages from Linguist
|
153
|
+
project.languages.keys.take(5)
|
154
|
+
end
|
155
|
+
|
156
|
+
def failure(msg)
|
157
|
+
cleanup
|
158
|
+
raise Theoj::Error, msg
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "yaml"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Theoj
|
6
|
+
class PublishedPaper
|
7
|
+
include Theoj::Git
|
8
|
+
|
9
|
+
attr_accessor :metadata
|
10
|
+
|
11
|
+
def initialize(doi)
|
12
|
+
doi_url = "https://doi.org/#{doi}"
|
13
|
+
doi_response = Faraday.get(doi_url)
|
14
|
+
if doi_response.status == 302
|
15
|
+
paper_url = doi_response.headers[:location]
|
16
|
+
else
|
17
|
+
raise Theoj::Error, "The DOI is invalid, url does not resolve #{doi_url}"
|
18
|
+
end
|
19
|
+
|
20
|
+
paper_data = Faraday.get(paper_url + ".json")
|
21
|
+
if paper_data.status == 200
|
22
|
+
@metadata = JSON.parse(paper_data.body, symbolize_names: true)
|
23
|
+
else
|
24
|
+
raise Theoj::Error, "Could not find the paper data at #{paper_url + ".json"}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
[:title, :state, :submitted_at, :doi, :published_at,
|
29
|
+
:volume, :issue, :year, :page, :authors, :editor,
|
30
|
+
:editor_name, :editor_url, :editor_orcid, :reviewers,
|
31
|
+
:languages, :tags, :software_repository, :paper_review,
|
32
|
+
:pdf_url, :software_archive].each do |method_name|
|
33
|
+
define_method(method_name) { metadata[method_name] }
|
34
|
+
define_method("#{method_name}=") {|value| @metadata[method_name] = value }
|
35
|
+
end
|
36
|
+
|
37
|
+
def yaml_metadata
|
38
|
+
metadata.transform_keys(&:to_s).to_yaml
|
39
|
+
end
|
40
|
+
|
41
|
+
def json_metadata
|
42
|
+
metadata.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module Theoj
|
4
|
+
class ReviewIssue
|
5
|
+
include Theoj::GitHub
|
6
|
+
|
7
|
+
attr_accessor :issue_id
|
8
|
+
attr_accessor :repository
|
9
|
+
attr_accessor :paper
|
10
|
+
attr_accessor :local_path
|
11
|
+
|
12
|
+
def initialize(repository, issue_id, access_token=nil)
|
13
|
+
@issue_id = issue_id
|
14
|
+
@repository = repository
|
15
|
+
@github_access_token = access_token
|
16
|
+
end
|
17
|
+
|
18
|
+
def issue_body
|
19
|
+
@issue_body ||= issue(repository, issue_id).body
|
20
|
+
end
|
21
|
+
|
22
|
+
def paper
|
23
|
+
@paper ||= Theoj::Paper.new(target_repository, paper_branch)
|
24
|
+
end
|
25
|
+
|
26
|
+
def target_repository
|
27
|
+
@target_repository ||= read_value_from_body("target-repository")
|
28
|
+
end
|
29
|
+
|
30
|
+
def reviewers
|
31
|
+
@reviewers ||= read_value_from_body("reviewers-list").split(",").map{|r| r.strip} - ["Pending", "TBD"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def editor
|
35
|
+
@editor ||= read_value_from_body("editor")
|
36
|
+
end
|
37
|
+
|
38
|
+
#@NeuroLibre -- START
|
39
|
+
# Removes @archive, uses the following instead.
|
40
|
+
def book_exec_url
|
41
|
+
@book_exec_url ||= read_value_from_body("book-exec-url")
|
42
|
+
end
|
43
|
+
|
44
|
+
def repository_archive
|
45
|
+
@repository_archive ||= read_value_from_body("repository-archive")
|
46
|
+
end
|
47
|
+
|
48
|
+
def data_archive
|
49
|
+
@data_archive ||= read_value_from_body("data-archive")
|
50
|
+
end
|
51
|
+
|
52
|
+
def book_archive
|
53
|
+
@book_archive ||= read_value_from_body("book-archive")
|
54
|
+
end
|
55
|
+
|
56
|
+
def docker_archive
|
57
|
+
@docker_archive ||= read_value_from_body("docker-archive")
|
58
|
+
end
|
59
|
+
#@NeuroLibre -- END
|
60
|
+
|
61
|
+
def version
|
62
|
+
@version ||= read_value_from_body("version")
|
63
|
+
end
|
64
|
+
|
65
|
+
def paper_branch
|
66
|
+
@paper_branch ||= read_value_from_body("branch")
|
67
|
+
end
|
68
|
+
|
69
|
+
def value_for(value_name)
|
70
|
+
read_value_from_body(value_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def read_from_body(start_mark, end_mark)
|
76
|
+
text = ""
|
77
|
+
issue_body.match(/#{start_mark}(.*)#{end_mark}/im) do |m|
|
78
|
+
text = m[1]
|
79
|
+
end
|
80
|
+
|
81
|
+
text = "" if ["Pending", "TBD"].include?(text.strip)
|
82
|
+
text.strip
|
83
|
+
end
|
84
|
+
|
85
|
+
# Read value in issue's body between HTML comments
|
86
|
+
def read_value_from_body(value_name)
|
87
|
+
start_mark = "<!--#{value_name}-->"
|
88
|
+
end_mark = "<!--end-#{value_name}-->"
|
89
|
+
read_from_body(start_mark, end_mark)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require "json"
|
2
|
+
require "date"
|
3
|
+
require "base64"
|
4
|
+
require "faraday"
|
5
|
+
require "commonmarker"
|
6
|
+
|
7
|
+
module Theoj
|
8
|
+
class Submission
|
9
|
+
include Theoj::GitHub
|
10
|
+
|
11
|
+
attr_accessor :journal
|
12
|
+
attr_accessor :review_issue
|
13
|
+
attr_accessor :paper
|
14
|
+
|
15
|
+
def initialize(journal, review_issue, paper=nil)
|
16
|
+
@journal = journal
|
17
|
+
@review_issue = review_issue
|
18
|
+
@paper = paper || @review_issue.paper
|
19
|
+
end
|
20
|
+
|
21
|
+
# @NeuroLibre -- START
|
22
|
+
# Removes archive_doi, adds neurolibre reproducibility assets DOIs.
|
23
|
+
def deposit_payload
|
24
|
+
{
|
25
|
+
id: metadata_info[:review_issue_id],
|
26
|
+
metadata: Base64.encode64(metadata_payload),
|
27
|
+
doi: metadata_info[:doi],
|
28
|
+
repository_doi: metadata_info[:repository_doi],
|
29
|
+
book_exec_url: metadata_info[:book_exec_url],
|
30
|
+
data_doi: metadata_info[:data_doi],
|
31
|
+
book_doi: metadata_info[:book_doi],
|
32
|
+
docker_doi: metadata_info[:docker_doi],
|
33
|
+
citation_string: citation_string,
|
34
|
+
title: metadata_info[:title]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
# @NeuroLibre -- END
|
38
|
+
|
39
|
+
# Create a metadata json payload
|
40
|
+
# @NeuroLibre -- START
|
41
|
+
# Removes archive_doi, adds neurolibre reproducibility assets DOIs.
|
42
|
+
def metadata_payload
|
43
|
+
{
|
44
|
+
paper: {
|
45
|
+
title: metadata_info[:title],
|
46
|
+
tags: metadata_info[:tags],
|
47
|
+
languages: metadata_info[:languages],
|
48
|
+
authors: metadata_info[:authors],
|
49
|
+
doi: metadata_info[:doi],
|
50
|
+
|
51
|
+
repository_doi: metadata_info[:repository_doi],
|
52
|
+
book_exec_url: metadata_info[:book_exec_url],
|
53
|
+
data_doi: metadata_info[:data_doi],
|
54
|
+
book_doi: metadata_info[:book_doi],
|
55
|
+
docker_doi: metadata_info[:docker_doi],
|
56
|
+
|
57
|
+
repository_address: metadata_info[:software_repository_url],
|
58
|
+
editor: metadata_info[:review_editor],
|
59
|
+
reviewers: metadata_info[:reviewers].collect(&:strip),
|
60
|
+
volume: metadata_info[:volume],
|
61
|
+
issue: metadata_info[:issue],
|
62
|
+
year: metadata_info[:year],
|
63
|
+
page: metadata_info[:page]
|
64
|
+
}
|
65
|
+
}.to_json
|
66
|
+
end
|
67
|
+
# @NeuroLibre -- END
|
68
|
+
|
69
|
+
# Create metadata used to generate PDF/JATS outputs
|
70
|
+
# @NeuroLibre -- START
|
71
|
+
# Removes archive_doi, adds neurolibre reproducibility assets DOIs.
|
72
|
+
def article_metadata
|
73
|
+
{
|
74
|
+
title: metadata_info[:title],
|
75
|
+
tags: metadata_info[:tags],
|
76
|
+
authors: metadata_info[:authors],
|
77
|
+
doi: metadata_info[:doi],
|
78
|
+
software_repository_url: metadata_info[:software_repository_url],
|
79
|
+
reviewers: metadata_info[:reviewers].collect{|r| user_login(r)},
|
80
|
+
volume: metadata_info[:volume],
|
81
|
+
issue: metadata_info[:issue],
|
82
|
+
year: metadata_info[:year],
|
83
|
+
page: metadata_info[:page],
|
84
|
+
journal_alias: metadata_info[:journal_alias],
|
85
|
+
software_review_url: metadata_info[:software_review_url],
|
86
|
+
|
87
|
+
repository_doi: metadata_info[:repository_doi],
|
88
|
+
book_exec_url: metadata_info[:book_exec_url],
|
89
|
+
data_doi: metadata_info[:data_doi],
|
90
|
+
book_doi: metadata_info[:book_doi],
|
91
|
+
docker_doi: metadata_info[:docker_doi],
|
92
|
+
|
93
|
+
citation_string: metadata_info[:citation_string],
|
94
|
+
editor: metadata_info[:editor],
|
95
|
+
submitted_at: metadata_info[:submitted_at],
|
96
|
+
published_at: metadata_info[:published_at]
|
97
|
+
}
|
98
|
+
end
|
99
|
+
# @NeuroLibre -- END
|
100
|
+
|
101
|
+
def metadata_info
|
102
|
+
@metadata_info ||= all_metadata
|
103
|
+
end
|
104
|
+
|
105
|
+
def deposit!(secret)
|
106
|
+
parameters = deposit_payload.merge(secret: secret)
|
107
|
+
Faraday.post(journal.data[:deposit_url], parameters.to_json, {"Content-Type" => "application/json"})
|
108
|
+
end
|
109
|
+
|
110
|
+
def citation_string
|
111
|
+
metadata_info[:citation_string]
|
112
|
+
end
|
113
|
+
|
114
|
+
def paper_id
|
115
|
+
journal.paper_id_from_issue(review_issue.issue_id)
|
116
|
+
end
|
117
|
+
|
118
|
+
def paper_doi
|
119
|
+
journal.paper_doi_for_id(paper_id)
|
120
|
+
end
|
121
|
+
|
122
|
+
# @NeuroLibre -- START
|
123
|
+
# Removes archive_doi, adds neurolibre reproducibility assets DOIs.
|
124
|
+
def all_metadata
|
125
|
+
metadata = {
|
126
|
+
title: plaintext(paper.title),
|
127
|
+
tags: paper.tags,
|
128
|
+
languages: paper.languages,
|
129
|
+
authors: paper.authors.collect { |a| a.to_h },
|
130
|
+
doi: paper_doi,
|
131
|
+
software_repository_url: review_issue.target_repository,
|
132
|
+
review_issue_id: review_issue.issue_id,
|
133
|
+
review_editor: review_issue.editor,
|
134
|
+
reviewers: review_issue.reviewers,
|
135
|
+
volume: journal.current_volume,
|
136
|
+
issue: journal.current_issue,
|
137
|
+
year: journal.current_year,
|
138
|
+
page: review_issue.issue_id,
|
139
|
+
journal_alias: journal.alias,
|
140
|
+
journal_name: journal.name,
|
141
|
+
software_review_url: journal.reviews_repository_url(review_issue.issue_id),
|
142
|
+
|
143
|
+
# Context changes from archive --> doi
|
144
|
+
repository_doi: review_issue.repository_archive,
|
145
|
+
data_doi: review_issue.data_archive,
|
146
|
+
book_doi: review_issue.book_archive,
|
147
|
+
docker_doi: review_issue.docker_archive,
|
148
|
+
# Context does not change for this
|
149
|
+
book_exec_url: review_issue.book_exec_url,
|
150
|
+
|
151
|
+
citation_author: paper.citation_author
|
152
|
+
}
|
153
|
+
# @NeuroLibre -- END
|
154
|
+
|
155
|
+
metadata.merge!(editor_info, dates_info)
|
156
|
+
metadata[:citation_string] = build_citation_string(metadata)
|
157
|
+
metadata
|
158
|
+
end
|
159
|
+
|
160
|
+
def editor_info
|
161
|
+
editor_info = { editor: {
|
162
|
+
github_user: user_login(review_issue.editor),
|
163
|
+
name: nil,
|
164
|
+
url: nil,
|
165
|
+
orcid: nil
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
if review_issue.editor
|
170
|
+
editor_lookup = Faraday.get(journal.url + "/editors/lookup/" + user_login(review_issue.editor))
|
171
|
+
if editor_lookup.status == 200
|
172
|
+
info = JSON.parse(editor_lookup.body, symbolize_names: true)
|
173
|
+
editor_info[:editor][:name] = info[:name]
|
174
|
+
editor_info[:editor][:url] = info[:url]
|
175
|
+
editor_info[:editor][:orcid] = info[:orcid]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
editor_info
|
180
|
+
end
|
181
|
+
|
182
|
+
def dates_info
|
183
|
+
dates_info = { submitted_at: nil, published_at: nil }
|
184
|
+
|
185
|
+
if review_issue.issue_id
|
186
|
+
paper_lookup = Faraday.get(journal.url + "/papers/lookup/" + review_issue.issue_id.to_s)
|
187
|
+
if paper_lookup.status == 200
|
188
|
+
info = JSON.parse(paper_lookup.body, symbolize_names: true)
|
189
|
+
dates_info[:submitted_at] = format_date(info[:submitted]) if info[:submitted]
|
190
|
+
dates_info[:published_at] = format_date(info[:accepted]) if info[:accepted]
|
191
|
+
end
|
192
|
+
|
193
|
+
if dates_info[:published_at]
|
194
|
+
yvi = journal.year_volume_issue_for_date(Date.parse(dates_info[:published_at]))
|
195
|
+
dates_info[:year] = yvi[0]
|
196
|
+
dates_info[:volume] = yvi[1]
|
197
|
+
dates_info[:issue] = yvi[2]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
dates_info
|
202
|
+
end
|
203
|
+
|
204
|
+
def track
|
205
|
+
track_info = { name: nil, short_name: nil, code: nil, label: nil, parameterized: nil}
|
206
|
+
|
207
|
+
if review_issue.issue_id
|
208
|
+
track_lookup = Faraday.get(journal.url + "/papers/" + review_issue.issue_id.to_s + "/lookup_track" )
|
209
|
+
if track_lookup.status == 200
|
210
|
+
track_info = JSON.parse(track_lookup.body, symbolize_names: true)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
track_info
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def build_citation_string(metadata)
|
220
|
+
"#{metadata[:citation_author]}, (#{metadata[:year]}). #{metadata[:title]}. #{metadata[:journal_name]}, #{metadata[:volume]}(#{metadata[:issue]}), #{metadata[:review_issue_id]}, https://doi.org/#{metadata[:doi]}"
|
221
|
+
end
|
222
|
+
|
223
|
+
def plaintext(t)
|
224
|
+
CommonMarker.render_doc(t, :DEFAULT).to_plaintext.strip.gsub(" ", " ").gsub("\n", " ")
|
225
|
+
end
|
226
|
+
|
227
|
+
def format_date(date_string)
|
228
|
+
Date.parse(date_string.to_s).strftime("%Y-%m-%d")
|
229
|
+
rescue Date::Error
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: neurolibre
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Juanjo Bazán
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-04-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: octokit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday-retry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: openjournals-nameable
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: github-linguist
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '7.24'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '7.24'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rugged
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.5'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: commonmarker
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.23'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.23'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 13.0.6
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 13.0.6
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.11'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.11'
|
139
|
+
description: A library to manage editorial objects used in the NeuroLibre's moderation
|
140
|
+
and screening process
|
141
|
+
email:
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- CHANGELOG.md
|
147
|
+
- LICENSE
|
148
|
+
- README.md
|
149
|
+
- lib/neurolibre.rb
|
150
|
+
- lib/theoj/author.rb
|
151
|
+
- lib/theoj/git.rb
|
152
|
+
- lib/theoj/github.rb
|
153
|
+
- lib/theoj/journal.rb
|
154
|
+
- lib/theoj/journals_data.rb
|
155
|
+
- lib/theoj/orcid.rb
|
156
|
+
- lib/theoj/paper.rb
|
157
|
+
- lib/theoj/published_paper.rb
|
158
|
+
- lib/theoj/review_issue.rb
|
159
|
+
- lib/theoj/submission.rb
|
160
|
+
- lib/theoj/version.rb
|
161
|
+
homepage: http://github.com/neurolibre/neurolibre-gem
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata:
|
165
|
+
bug_tracker_uri: https://github.com/neurolibre/neurolibre-gem/issues
|
166
|
+
changelog_uri: https://github.com/neurolibre/neurolibre-gem/blob/main/CHANGELOG.md
|
167
|
+
documentation_uri: https://www.rubydoc.info/gems/neurolibre
|
168
|
+
homepage_uri: http://github.com/neurolibre/neurolibre-gem
|
169
|
+
source_code_uri: http://github.com/neurolibre/neurolibre-gem
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options:
|
172
|
+
- "--main"
|
173
|
+
- README.md
|
174
|
+
- "--charset=UTF-8"
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
requirements: []
|
188
|
+
rubygems_version: 3.4.6
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: Editorial objects used by NeuroLibre
|
192
|
+
test_files: []
|