Working prototype
This commit is contained in:
parent
3ff4a6bba1
commit
afc7c4f6c9
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
samples/**/*
|
||||
1
docker/.gitignore
vendored
Normal file
1
docker/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
files/**/*
|
||||
143
docker/Dockerfile
Normal file
143
docker/Dockerfile
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
FROM alpine:3.7
|
||||
|
||||
LABEL maintainer="Lucas G. Diedrich <lucas.diedrich@gmail.com>"
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
ENV COMPOSER_ALLOW_SUPERUSER=1 \
|
||||
SERVERNAME="localhost" \
|
||||
OJS_VERSION="ojs-3_1_1-4" \
|
||||
OJS_CLI_INSTALL="1" \
|
||||
OJS_DB_HOST="mysql-ojs" \
|
||||
OJS_DB_USER="ojs" \
|
||||
OJS_DB_PASSWORD="ojs" \
|
||||
OJS_DB_NAME="ojs" \
|
||||
OJS_WEB_CONF="/etc/apache2/conf.d/ojs.conf" \
|
||||
OJS_CONF="/var/www/html/config.inc.php" \
|
||||
PACKAGES="supervisor dcron apache2 apache2-ssl apache2-utils php5 php5-fpm php5-cli php5-apache2 php5-zlib \
|
||||
php5-json php5-phar php5-openssl php5-mysql php5-curl php5-mcrypt php5-pdo_mysql php5-ctype \
|
||||
php5-gd php5-xml php5-dom php5-iconv curl nodejs git nano" \
|
||||
EXCLUDE="dbscripts/xml/data/locale/en_US/sample.xml \
|
||||
dbscripts/xml/data/sample.xml \
|
||||
docs/dev \
|
||||
tests \
|
||||
tools/buildpkg.sh \
|
||||
tools/genLocaleReport.sh \
|
||||
tools/genTestLocale.php \
|
||||
tools/test \
|
||||
lib/pkp/tools/travis \
|
||||
lib/pkp/plugins/*/*/tests \
|
||||
plugins/*/*/tests \
|
||||
plugins/auth/ldap \
|
||||
plugins/generic/announcementFeed \
|
||||
plugins/generic/backup \
|
||||
plugins/generic/browse \
|
||||
plugins/generic/coins \
|
||||
plugins/generic/cookiesAlert \
|
||||
plugins/generic/counter \
|
||||
plugins/generic/customLocale \
|
||||
plugins/generic/externalFeed \
|
||||
plugins/generic/lucene \
|
||||
plugins/generic/phpMyVisites \
|
||||
plugins/generic/recommendBySimilarity \
|
||||
plugins/generic/translator \
|
||||
plugins/importexport/sample \
|
||||
plugins/importexport/duracloud \
|
||||
plugins/reports/subscriptions \
|
||||
plugins/blocks/relatedItems \
|
||||
plugins/oaiMetadataFormats/jats \
|
||||
tests \
|
||||
lib/pkp/tests \
|
||||
.git \
|
||||
.openshift \
|
||||
.scrutinizer.yml \
|
||||
.travis.yml \
|
||||
lib/pkp/.git \
|
||||
lib/pkp/lib/components/*.js \
|
||||
lib/pkp/lib/components/*.css \
|
||||
lib/pkp/js/lib/pnotify/build-tools \
|
||||
lib/pkp/lib/vendor/alex198710/pnotify/.git \
|
||||
lib/pkp/lib/vendor/sebastian \
|
||||
lib/pkp/lib/vendor/oyejorge/less.php/test \
|
||||
lib/pkp/tools/travis \
|
||||
lib/pkp/lib/swordappv2/.git \
|
||||
lib/pkp/lib/swordappv2/.git \
|
||||
lib/pkp/lib/swordappv2/test \
|
||||
plugins/paymethod/paypal/vendor/omnipay/common/tests/ \
|
||||
plugins/paymethod/paypal/vendor/omnipay/paypal/tests/ \
|
||||
plugins/paymethod/paypal/vendor/guzzle/guzzle/docs/ \
|
||||
plugins/paymethod/paypal/vendor/guzzle/guzzle/tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/debug/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/console/Tests/ \
|
||||
plugins/paymethod/paypal/vendor/symfony/http-foundation/Tests/ \
|
||||
plugins/paymethod/paypal/vendor/symfony/event-dispatcher/ \
|
||||
plugins/paymethod/paypal/vendor/guzzle/guzzle/tests/Guzzle/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/filesystem/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/stopwatch/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/event-dispatcher/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/config/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/yaml/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/guzzle/guzzle/tests/Guzzle/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/symfony/config/Tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/citation-style-language/locales/.git \
|
||||
lib/pkp/lib/vendor/symfony/translation/Tests/ \
|
||||
lib/pkp/lib/vendor/symfony/process/Tests/ \
|
||||
lib/pkp/lib/vendor/pimple/pimple/src/Pimple/Tests/ \
|
||||
lib/pkp/lib/vendor/robloach/component-installer/tests/ComponentInstaller/Test/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/satooshi/php-coveralls/tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/guzzle/guzzle/tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/seboettg/collection/tests/ \
|
||||
plugins/generic/citationStyleLanguage/lib/vendor/seboettg/citeproc-php/tests/ \
|
||||
lib/pkp/lib/vendor/nikic/fast-route/test/ \
|
||||
lib/pkp/lib/vendor/ezyang/htmlpurifier/tests/ \
|
||||
lib/pkp/lib/vendor/ezyang/htmlpurifier/smoketests/ \
|
||||
lib/pkp/lib/vendor/pimple/pimple/ext/pimple/tests/ \
|
||||
lib/pkp/lib/vendor/robloach/component-installer/tests/ \
|
||||
lib/pkp/lib/vendor/phpmailer/phpmailer/test/ \
|
||||
node_modules \
|
||||
.babelrc \
|
||||
.editorconfig \
|
||||
.eslintignore \
|
||||
.eslintrc.js \
|
||||
.postcssrc.js \
|
||||
package.json \
|
||||
webpack.config.js \
|
||||
lib/ui-library \
|
||||
/usr/local/bin/composer \
|
||||
/root/.composer \
|
||||
/root/.npm \
|
||||
/var/cache/apk/* "
|
||||
|
||||
RUN apk add --update --no-cache $PACKAGES && \
|
||||
ln -s /usr/bin/php5 /usr/bin/php && \
|
||||
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
|
||||
# Configure and download code from git
|
||||
git config --global url.https://.insteadOf git:// && \
|
||||
git config --global advice.detachedHead false && \
|
||||
git clone --depth 1 --single-branch --branch $OJS_VERSION --progress https://github.com/pkp/ojs.git . && \
|
||||
git submodule update --init --recursive >/dev/null && \
|
||||
# Install NPM and Composer Deps
|
||||
composer update -d lib/pkp --no-dev && \
|
||||
composer install -d plugins/paymethod/paypal --no-dev && \
|
||||
composer install -d plugins/generic/citationStyleLanguage --no-dev && \
|
||||
npm install -y && npm run build && \
|
||||
# Create directories
|
||||
mkdir -p /var/www/html/files /run/apache2 /run/supervisord/ && \
|
||||
cp config.TEMPLATE.inc.php config.inc.php && \
|
||||
chown -R apache:apache /var/www/* && \
|
||||
# Prepare crontab
|
||||
echo "0 * * * * ojs-run-scheduled" | crontab - && \
|
||||
# Prepare httpd.conf
|
||||
sed -i -e '\#<Directory />#,\#</Directory>#d' /etc/apache2/httpd.conf && \
|
||||
sed -i -e "s/^ServerSignature.*/ServerSignature Off/" /etc/apache2/httpd.conf && \
|
||||
# Clear the image
|
||||
apk del --no-cache nodejs git && rm -rf $EXCLUDE && \
|
||||
find . \( -name .gitignore -o -name .gitmodules -o -name .keepme \) -exec rm '{}' \;
|
||||
|
||||
COPY files/ /
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
VOLUME [ "/var/www/html/files", "/var/www/html/public" ]
|
||||
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
||||
43
docker/docker-compose.yml
Normal file
43
docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
version: "3.3"
|
||||
services:
|
||||
mysql-ojs-3114:
|
||||
image: mysql:5.7
|
||||
container_name: mysql-ojs-3114
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ojs
|
||||
MYSQL_DATABASE: ojs
|
||||
MYSQL_USER: ojs
|
||||
MYSQL_PASSWORD: ojs
|
||||
pkp-ojs-3114:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name : pkp-ojs-3114
|
||||
restart: always
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "8443:443"
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime # to sync the container clock with localhost.
|
||||
- ./files/private:/var/www/files # ojs' private files
|
||||
- ./files/public:/var/www/html/public # ojs' public files
|
||||
- ./files/logs:/var/log/apache2 # apache logs
|
||||
|
||||
# - ./config/ojs.config.inc.php:/var/www/html/config.inc.php # ojs' config
|
||||
# - ./config/apache.htaccess:/var/www/html/.htaccess # ojs' htaccess
|
||||
# - ./config/php.custom.ini:/usr/local/etc/php/conf.d/custom.ini # php config
|
||||
environment:
|
||||
SERVERNAME: 'localhost'
|
||||
OJS_CLI_INSTALL: 1
|
||||
OJS_DB_HOST: 'mysql-ojs-3114'
|
||||
depends_on:
|
||||
- mysql-ojs-3114
|
||||
# labels:
|
||||
# - traefik.backend=ojs
|
||||
# - traefik.frontend.rule=Host:myserver.mydomain
|
||||
# - traefik.docker.network=proxy
|
||||
# - traefik.port=8080
|
||||
# networks:
|
||||
# - internal
|
||||
# - proxy
|
||||
100
docs/backup_config.txt
Normal file
100
docs/backup_config.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
Информация о сервере
|
||||
Задаем название Задаем значение
|
||||
ОС платформы Linux
|
||||
Версия PHP 5.6.32-5.6.32+mh2
|
||||
Версия Apache Apache
|
||||
Драйвер базы данных mysql
|
||||
Версия СУБД 5.6.40-log
|
||||
Конфигурация OJS
|
||||
Задаем название Задаем значение
|
||||
general
|
||||
installed включено
|
||||
base_url http://pkp.sfu.ca/ojs
|
||||
session_cookie_name OJSSID
|
||||
session_lifetime 30
|
||||
scheduled_tasks отключено
|
||||
time_zone UTC
|
||||
date_format_trunc %m-%d
|
||||
date_format_short %Y-%m-%d
|
||||
date_format_long %B %e, %Y
|
||||
datetime_format_short %Y-%m-%d %I:%M %p
|
||||
datetime_format_long %B %e, %Y - %I:%M %p
|
||||
time_format %I:%M %p
|
||||
disable_path_info отключено
|
||||
allow_url_fopen отключено
|
||||
restful_urls отключено
|
||||
trust_x_forwarded_for отключено
|
||||
enable_cdn включено
|
||||
citation_checking_max_processes 3
|
||||
show_upgrade_warning включено
|
||||
enable_minified отключено
|
||||
enable_beacon отключено
|
||||
database
|
||||
driver mysql
|
||||
host u51131.mysql.masterhost.ru
|
||||
username u51131_vp
|
||||
password ser2po6ato
|
||||
name u51131_ojs3
|
||||
persistent отключено
|
||||
debug отключено
|
||||
cache
|
||||
object_cache none
|
||||
memcache_hostname localhost
|
||||
memcache_port 11211
|
||||
web_cache отключено
|
||||
web_cache_hours 1
|
||||
i18n
|
||||
locale ru_RU
|
||||
client_charset utf-8
|
||||
connection_charset отключено
|
||||
database_charset отключено
|
||||
charset_normalization отключено
|
||||
files
|
||||
files_dir /home/u51131/ojs3.gpmu.org/uploads
|
||||
public_files_dir public
|
||||
umask 18
|
||||
filename_revision_match 70
|
||||
finfo
|
||||
Нет элементов
|
||||
security
|
||||
force_ssl отключено
|
||||
force_login_ssl отключено
|
||||
session_check_ip включено
|
||||
encryption sha1
|
||||
salt YouMustSetASecretKeyHere!!
|
||||
api_key_secret
|
||||
reset_seconds 7200
|
||||
allowed_html a[href|target|title],em,strong,cite,code,ul,ol,li[class],dl,dt,dd,b,i,u,img[src|alt],sup,sub,br,p
|
||||
email
|
||||
time_between_emails 3600
|
||||
max_recipients 10
|
||||
require_validation отключено
|
||||
validation_timeout 14
|
||||
search
|
||||
min_word_length 3
|
||||
results_per_keyword 500
|
||||
result_cache_hours 1
|
||||
oai
|
||||
oai включено
|
||||
repository_id repid_1
|
||||
oai_max_records 100
|
||||
interface
|
||||
items_per_page 25
|
||||
page_links 10
|
||||
captcha
|
||||
recaptcha отключено
|
||||
recaptcha_public_key your_public_key
|
||||
recaptcha_private_key your_private_key
|
||||
captcha_on_register включено
|
||||
cli
|
||||
perl /usr/bin/perl
|
||||
tar /bin/tar
|
||||
xslt_command
|
||||
proxy
|
||||
Нет элементов
|
||||
debug
|
||||
show_stacktrace отключено
|
||||
display_errors отключено
|
||||
deprecation_warnings отключено
|
||||
log_web_service_info отключено
|
||||
39
docs/roadmap.md
Normal file
39
docs/roadmap.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Journals:
|
||||
- [x] Creation
|
||||
- [ ] Error handling
|
||||
|
||||
# Issues:
|
||||
- [x] Creation
|
||||
|
||||
|
||||
# Submissions:
|
||||
- Creation
|
||||
- [x] Get userGroupId & sectionId
|
||||
- [x] Step1: checkboxes + get submissionId
|
||||
- [x] Step2: Get genreId
|
||||
- [x] Step2: upload material
|
||||
- [x] Step2: save
|
||||
- [x] Step3: metadata (title, abstact, keywords)
|
||||
- [x] Step4: confirmation
|
||||
- [ ] Galley
|
||||
- [ ] Add galley
|
||||
- [ ] Get assocId & genreId from upload form
|
||||
- [x] Add author
|
||||
- [x] Get userGroupId
|
||||
- [x] Add author info
|
||||
- [ ] Delete default author (admin)
|
||||
- [x] Attach to issue
|
||||
|
||||
# Importer:
|
||||
- [x] Select journal to upload issue to
|
||||
- [ ] XML processing
|
||||
- [x] Find all XMLs in provided directory
|
||||
- [x] Validate and parse each XML
|
||||
- [x] Collect info object
|
||||
- [ ] Create journal
|
||||
- [x] Create issue
|
||||
- [ ]
|
||||
- [ ]
|
||||
|
||||
|
||||
|
||||
11
email-patch/AuthorForm.inc.php.patch
Normal file
11
email-patch/AuthorForm.inc.php.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- AuthorForm.inc.php 2019-03-13 06:36:56.547370700 +0300
|
||||
+++ AuthorForm.inc.old.php 2019-03-13 06:36:46.571352100 +0300
|
||||
@@ -37,7 +37,7 @@
|
||||
// Validation checks for this form
|
||||
$this->addCheck(new FormValidator($this, 'firstName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
$this->addCheck(new FormValidator($this, 'lastName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
- $this->addCheck(new FormValidatorEmail($this, 'email', 'optional', 'form.emailRequired'));
|
||||
+ $this->addCheck(new FormValidatorEmail($this, 'email', 'required', 'form.emailRequired'));
|
||||
$this->addCheck(new FormValidatorUrl($this, 'userUrl', 'optional', 'user.profile.form.urlInvalid'));
|
||||
$this->addCheck(new FormValidator($this, 'userGroupId', 'required', 'submission.submit.form.contributorRoleRequired'));
|
||||
$this->addCheck(new FormValidatorORCID($this, 'orcid', 'optional', 'user.orcid.orcidInvalid'));
|
||||
13
email-patch/README.md
Normal file
13
email-patch/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
## OJS patch for email fields to be optional on author form during submission creation
|
||||
|
||||
Tested only on OJS v. 3.1.1.2 and 3.1.1.4
|
||||
Patch is probably incompatible with later versions
|
||||
|
||||
## Installation:
|
||||
|
||||
### Either:
|
||||
Copy userDetails.tpl to [/var/www/html/lib/pkp/templates/common]
|
||||
Copy authorForm.tpl to [/var/www/html/lib/pkp/templates/controllers/grid/users/author/form]
|
||||
Copy AuthorForm.inc.php to [/var/www/lib/pkp/controllers/grid/users/author/form]
|
||||
|
||||
### OR: just apply goddamn patches
|
||||
10
email-patch/authorForm.patch
Normal file
10
email-patch/authorForm.patch
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
--- authorForm_old.tpl 2019-03-13 05:30:57.527000000 +0300
|
||||
+++ authorForm.tpl 2019-03-13 05:30:57.527000000 +0300
|
||||
@@ -36,6 +36,7 @@
|
||||
disableSignatureSection=true
|
||||
extraContentSectionUnfolded=true
|
||||
countryRequired=true
|
||||
+ emailIsOptional=true
|
||||
}
|
||||
|
||||
{fbvFormArea id="submissionSpecific"}
|
||||
233
email-patch/source/AuthorForm.inc.old.php
Normal file
233
email-patch/source/AuthorForm.inc.old.php
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file controllers/grid/users/author/form/AuthorForm.inc.php
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class AuthorForm
|
||||
* @ingroup controllers_grid_users_author_form
|
||||
*
|
||||
* @brief Form for adding/editing a author
|
||||
*/
|
||||
|
||||
import('lib.pkp.classes.form.Form');
|
||||
|
||||
class AuthorForm extends Form {
|
||||
/** The submission associated with the submission contributor being edited **/
|
||||
var $_submission;
|
||||
|
||||
/** Author the author being edited **/
|
||||
var $_author;
|
||||
|
||||
/** The type of submission Id **/
|
||||
var $_submissionIdFieldName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
function __construct($submission, $author, $submissionIdFieldName) {
|
||||
parent::__construct('controllers/grid/users/author/form/authorForm.tpl');
|
||||
$this->setSubmission($submission);
|
||||
$this->setAuthor($author);
|
||||
$this->setSubmissionIdFieldName($submissionIdFieldName);
|
||||
|
||||
// Validation checks for this form
|
||||
$this->addCheck(new FormValidator($this, 'firstName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
$this->addCheck(new FormValidator($this, 'lastName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
$this->addCheck(new FormValidatorEmail($this, 'email', 'required', 'form.emailRequired'));
|
||||
$this->addCheck(new FormValidatorUrl($this, 'userUrl', 'optional', 'user.profile.form.urlInvalid'));
|
||||
$this->addCheck(new FormValidator($this, 'userGroupId', 'required', 'submission.submit.form.contributorRoleRequired'));
|
||||
$this->addCheck(new FormValidatorORCID($this, 'orcid', 'optional', 'user.orcid.orcidInvalid'));
|
||||
$this->addCheck(new FormValidatorPost($this));
|
||||
$this->addCheck(new FormValidatorCSRF($this));
|
||||
}
|
||||
|
||||
//
|
||||
// Getters and Setters
|
||||
//
|
||||
/**
|
||||
* Get the author
|
||||
* @return Author
|
||||
*/
|
||||
function getAuthor() {
|
||||
return $this->_author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the author
|
||||
* @param @author Author
|
||||
*/
|
||||
function setAuthor($author) {
|
||||
$this->_author = $author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Submission
|
||||
* @return Submission
|
||||
*/
|
||||
function getSubmission() {
|
||||
return $this->_submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Submission
|
||||
* @param Submission
|
||||
*/
|
||||
function setSubmission($submission) {
|
||||
$this->_submission = $submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Submission Id field name
|
||||
* @return String
|
||||
*/
|
||||
function getSubmissionIdFieldName() {
|
||||
return $this->_submissionIdFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Submission Id field name
|
||||
* @param String
|
||||
*/
|
||||
function setSubmissionIdFieldName($submissionIdFieldName) {
|
||||
$this->_submissionIdFieldName = $submissionIdFieldName;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Overridden template methods
|
||||
//
|
||||
/**
|
||||
* Initialize form data from the associated author.
|
||||
* @param $author Author
|
||||
*/
|
||||
function initData() {
|
||||
$author = $this->getAuthor();
|
||||
|
||||
if ($author) {
|
||||
$this->_data = array(
|
||||
'authorId' => $author->getId(),
|
||||
'firstName' => $author->getFirstName(),
|
||||
'middleName' => $author->getMiddleName(),
|
||||
'lastName' => $author->getLastName(),
|
||||
'suffix' => $author->getSuffix(),
|
||||
'affiliation' => $author->getAffiliation(null), // Localized
|
||||
'country' => $author->getCountry(),
|
||||
'email' => $author->getEmail(),
|
||||
'userUrl' => $author->getUrl(),
|
||||
'orcid' => $author->getOrcid(),
|
||||
'userGroupId' => $author->getUserGroupId(),
|
||||
'biography' => $author->getBiography(null),
|
||||
'primaryContact' => $author->getPrimaryContact(),
|
||||
'includeInBrowse' => $author->getIncludeInBrowse(),
|
||||
);
|
||||
} else {
|
||||
// assume authors should be listed unless otherwise specified.
|
||||
$this->_data = array('includeInBrowse' => true);
|
||||
}
|
||||
// in order to be able to use the hook
|
||||
return parent::initData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the form.
|
||||
* @see Form::fetch()
|
||||
*/
|
||||
function fetch($request) {
|
||||
$author = $this->getAuthor();
|
||||
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$countryDao = DAORegistry::getDAO('CountryDAO');
|
||||
$countries = $countryDao->getCountries();
|
||||
$templateMgr->assign('countries', $countries);
|
||||
|
||||
$router = $request->getRouter();
|
||||
$context = $router->getContext($request);
|
||||
|
||||
$userGroupDao = DAORegistry::getDAO('UserGroupDAO');
|
||||
$authorUserGroups = $userGroupDao->getByRoleId($context->getId(), ROLE_ID_AUTHOR);
|
||||
$templateMgr->assign('authorUserGroups', $authorUserGroups);
|
||||
|
||||
$submission = $this->getSubmission();
|
||||
$templateMgr->assign('submissionIdFieldName', $this->getSubmissionIdFieldName());
|
||||
$templateMgr->assign('submissionId', $submission->getId());
|
||||
|
||||
return parent::fetch($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign form data to user-submitted data.
|
||||
* @see Form::readInputData()
|
||||
*/
|
||||
function readInputData() {
|
||||
$this->readUserVars(array(
|
||||
'authorId',
|
||||
'firstName',
|
||||
'middleName',
|
||||
'lastName',
|
||||
'suffix',
|
||||
'affiliation',
|
||||
'country',
|
||||
'email',
|
||||
'userUrl',
|
||||
'orcid',
|
||||
'userGroupId',
|
||||
'biography',
|
||||
'primaryContact',
|
||||
'includeInBrowse',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save author
|
||||
* @see Form::execute()
|
||||
* @see Form::execute()
|
||||
*/
|
||||
function execute() {
|
||||
$authorDao = DAORegistry::getDAO('AuthorDAO');
|
||||
$submission = $this->getSubmission();
|
||||
|
||||
$author = $this->getAuthor();
|
||||
if (!$author) {
|
||||
// this is a new submission contributor
|
||||
$this->_author = new Author();
|
||||
$author = $this->getAuthor();
|
||||
$author->setSubmissionId($submission->getId());
|
||||
$existingAuthor = false;
|
||||
} else {
|
||||
$existingAuthor = true;
|
||||
if ($submission->getId() !== $author->getSubmissionId()) fatalError('Invalid author!');
|
||||
}
|
||||
|
||||
$author->setFirstName($this->getData('firstName'));
|
||||
$author->setMiddleName($this->getData('middleName'));
|
||||
$author->setLastName($this->getData('lastName'));
|
||||
$author->setSuffix($this->getData('suffix'));
|
||||
$author->setAffiliation($this->getData('affiliation'), null); // localized
|
||||
$author->setCountry($this->getData('country'));
|
||||
$author->setEmail($this->getData('email'));
|
||||
$author->setUrl($this->getData('userUrl'));
|
||||
$author->setOrcid($this->getData('orcid'));
|
||||
$author->setUserGroupId($this->getData('userGroupId'));
|
||||
$author->setBiography($this->getData('biography'), null); // localized
|
||||
$author->setPrimaryContact(($this->getData('primaryContact') ? true : false));
|
||||
$author->setIncludeInBrowse(($this->getData('includeInBrowse') ? true : false));
|
||||
|
||||
// in order to be able to use the hook
|
||||
parent::execute();
|
||||
|
||||
if ($existingAuthor) {
|
||||
$authorDao->updateObject($author);
|
||||
$authorId = $author->getId();
|
||||
} else {
|
||||
$authorId = $authorDao->insertObject($author);
|
||||
}
|
||||
|
||||
return $authorId;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
233
email-patch/source/AuthorForm.inc.php
Normal file
233
email-patch/source/AuthorForm.inc.php
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file controllers/grid/users/author/form/AuthorForm.inc.php
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class AuthorForm
|
||||
* @ingroup controllers_grid_users_author_form
|
||||
*
|
||||
* @brief Form for adding/editing a author
|
||||
*/
|
||||
|
||||
import('lib.pkp.classes.form.Form');
|
||||
|
||||
class AuthorForm extends Form {
|
||||
/** The submission associated with the submission contributor being edited **/
|
||||
var $_submission;
|
||||
|
||||
/** Author the author being edited **/
|
||||
var $_author;
|
||||
|
||||
/** The type of submission Id **/
|
||||
var $_submissionIdFieldName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
function __construct($submission, $author, $submissionIdFieldName) {
|
||||
parent::__construct('controllers/grid/users/author/form/authorForm.tpl');
|
||||
$this->setSubmission($submission);
|
||||
$this->setAuthor($author);
|
||||
$this->setSubmissionIdFieldName($submissionIdFieldName);
|
||||
|
||||
// Validation checks for this form
|
||||
$this->addCheck(new FormValidator($this, 'firstName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
$this->addCheck(new FormValidator($this, 'lastName', 'required', 'submission.submit.form.authorRequiredFields'));
|
||||
$this->addCheck(new FormValidatorEmail($this, 'email', 'optional', 'form.emailRequired'));
|
||||
$this->addCheck(new FormValidatorUrl($this, 'userUrl', 'optional', 'user.profile.form.urlInvalid'));
|
||||
$this->addCheck(new FormValidator($this, 'userGroupId', 'required', 'submission.submit.form.contributorRoleRequired'));
|
||||
$this->addCheck(new FormValidatorORCID($this, 'orcid', 'optional', 'user.orcid.orcidInvalid'));
|
||||
$this->addCheck(new FormValidatorPost($this));
|
||||
$this->addCheck(new FormValidatorCSRF($this));
|
||||
}
|
||||
|
||||
//
|
||||
// Getters and Setters
|
||||
//
|
||||
/**
|
||||
* Get the author
|
||||
* @return Author
|
||||
*/
|
||||
function getAuthor() {
|
||||
return $this->_author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the author
|
||||
* @param @author Author
|
||||
*/
|
||||
function setAuthor($author) {
|
||||
$this->_author = $author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Submission
|
||||
* @return Submission
|
||||
*/
|
||||
function getSubmission() {
|
||||
return $this->_submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Submission
|
||||
* @param Submission
|
||||
*/
|
||||
function setSubmission($submission) {
|
||||
$this->_submission = $submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Submission Id field name
|
||||
* @return String
|
||||
*/
|
||||
function getSubmissionIdFieldName() {
|
||||
return $this->_submissionIdFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Submission Id field name
|
||||
* @param String
|
||||
*/
|
||||
function setSubmissionIdFieldName($submissionIdFieldName) {
|
||||
$this->_submissionIdFieldName = $submissionIdFieldName;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Overridden template methods
|
||||
//
|
||||
/**
|
||||
* Initialize form data from the associated author.
|
||||
* @param $author Author
|
||||
*/
|
||||
function initData() {
|
||||
$author = $this->getAuthor();
|
||||
|
||||
if ($author) {
|
||||
$this->_data = array(
|
||||
'authorId' => $author->getId(),
|
||||
'firstName' => $author->getFirstName(),
|
||||
'middleName' => $author->getMiddleName(),
|
||||
'lastName' => $author->getLastName(),
|
||||
'suffix' => $author->getSuffix(),
|
||||
'affiliation' => $author->getAffiliation(null), // Localized
|
||||
'country' => $author->getCountry(),
|
||||
'email' => $author->getEmail(),
|
||||
'userUrl' => $author->getUrl(),
|
||||
'orcid' => $author->getOrcid(),
|
||||
'userGroupId' => $author->getUserGroupId(),
|
||||
'biography' => $author->getBiography(null),
|
||||
'primaryContact' => $author->getPrimaryContact(),
|
||||
'includeInBrowse' => $author->getIncludeInBrowse(),
|
||||
);
|
||||
} else {
|
||||
// assume authors should be listed unless otherwise specified.
|
||||
$this->_data = array('includeInBrowse' => true);
|
||||
}
|
||||
// in order to be able to use the hook
|
||||
return parent::initData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the form.
|
||||
* @see Form::fetch()
|
||||
*/
|
||||
function fetch($request) {
|
||||
$author = $this->getAuthor();
|
||||
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$countryDao = DAORegistry::getDAO('CountryDAO');
|
||||
$countries = $countryDao->getCountries();
|
||||
$templateMgr->assign('countries', $countries);
|
||||
|
||||
$router = $request->getRouter();
|
||||
$context = $router->getContext($request);
|
||||
|
||||
$userGroupDao = DAORegistry::getDAO('UserGroupDAO');
|
||||
$authorUserGroups = $userGroupDao->getByRoleId($context->getId(), ROLE_ID_AUTHOR);
|
||||
$templateMgr->assign('authorUserGroups', $authorUserGroups);
|
||||
|
||||
$submission = $this->getSubmission();
|
||||
$templateMgr->assign('submissionIdFieldName', $this->getSubmissionIdFieldName());
|
||||
$templateMgr->assign('submissionId', $submission->getId());
|
||||
|
||||
return parent::fetch($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign form data to user-submitted data.
|
||||
* @see Form::readInputData()
|
||||
*/
|
||||
function readInputData() {
|
||||
$this->readUserVars(array(
|
||||
'authorId',
|
||||
'firstName',
|
||||
'middleName',
|
||||
'lastName',
|
||||
'suffix',
|
||||
'affiliation',
|
||||
'country',
|
||||
'email',
|
||||
'userUrl',
|
||||
'orcid',
|
||||
'userGroupId',
|
||||
'biography',
|
||||
'primaryContact',
|
||||
'includeInBrowse',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save author
|
||||
* @see Form::execute()
|
||||
* @see Form::execute()
|
||||
*/
|
||||
function execute() {
|
||||
$authorDao = DAORegistry::getDAO('AuthorDAO');
|
||||
$submission = $this->getSubmission();
|
||||
|
||||
$author = $this->getAuthor();
|
||||
if (!$author) {
|
||||
// this is a new submission contributor
|
||||
$this->_author = new Author();
|
||||
$author = $this->getAuthor();
|
||||
$author->setSubmissionId($submission->getId());
|
||||
$existingAuthor = false;
|
||||
} else {
|
||||
$existingAuthor = true;
|
||||
if ($submission->getId() !== $author->getSubmissionId()) fatalError('Invalid author!');
|
||||
}
|
||||
|
||||
$author->setFirstName($this->getData('firstName'));
|
||||
$author->setMiddleName($this->getData('middleName'));
|
||||
$author->setLastName($this->getData('lastName'));
|
||||
$author->setSuffix($this->getData('suffix'));
|
||||
$author->setAffiliation($this->getData('affiliation'), null); // localized
|
||||
$author->setCountry($this->getData('country'));
|
||||
$author->setEmail($this->getData('email'));
|
||||
$author->setUrl($this->getData('userUrl'));
|
||||
$author->setOrcid($this->getData('orcid'));
|
||||
$author->setUserGroupId($this->getData('userGroupId'));
|
||||
$author->setBiography($this->getData('biography'), null); // localized
|
||||
$author->setPrimaryContact(($this->getData('primaryContact') ? true : false));
|
||||
$author->setIncludeInBrowse(($this->getData('includeInBrowse') ? true : false));
|
||||
|
||||
// in order to be able to use the hook
|
||||
parent::execute();
|
||||
|
||||
if ($existingAuthor) {
|
||||
$authorDao->updateObject($author);
|
||||
$authorId = $author->getId();
|
||||
} else {
|
||||
$authorId = $authorDao->insertObject($author);
|
||||
}
|
||||
|
||||
return $authorId;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
66
email-patch/source/authorForm.old.tpl
Normal file
66
email-patch/source/authorForm.old.tpl
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{**
|
||||
* templates/controllers/grid/users/author/form/authorForm.tpl
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Submission Contributor grid form
|
||||
*
|
||||
*}
|
||||
|
||||
<script>
|
||||
$(function() {ldelim}
|
||||
$('#editAuthor').pkpHandler(
|
||||
'$.pkp.controllers.form.AjaxFormHandler'
|
||||
);
|
||||
{rdelim});
|
||||
</script>
|
||||
|
||||
<form class="pkp_form" id="editAuthor" method="post" action="{url op="updateAuthor" authorId=$authorId}">
|
||||
{csrf}
|
||||
{include file="controllers/notification/inPlaceNotification.tpl" notificationId="authorFormNotification"}
|
||||
|
||||
{include
|
||||
file="common/userDetails.tpl"
|
||||
disableUserNameSection=true
|
||||
disableAuthSourceSection=true
|
||||
disablePasswordSection=true
|
||||
disableSendNotifySection=true
|
||||
disableSalutationSection=true
|
||||
disableInitialsSection=true
|
||||
disablePhoneSection=true
|
||||
disableLocaleSection=true
|
||||
disableInterestsSection=true
|
||||
disableMailingSection=true
|
||||
disableSignatureSection=true
|
||||
extraContentSectionUnfolded=true
|
||||
countryRequired=true
|
||||
}
|
||||
|
||||
{fbvFormArea id="submissionSpecific"}
|
||||
{fbvFormSection id="userGroupId" title="submission.submit.contributorRole" list=true required=true}
|
||||
{iterate from=authorUserGroups item=userGroup}
|
||||
{if $userGroupId == $userGroup->getId()}{assign var="checked" value=true}{else}{assign var="checked" value=false}{/if}
|
||||
{fbvElement type="radio" id="userGroup"|concat:$userGroup->getId() name="userGroupId" value=$userGroup->getId() checked=$checked label=$userGroup->getLocalizedName() translate=false}
|
||||
{/iterate}
|
||||
{/fbvFormSection}
|
||||
{fbvFormSection list="true"}
|
||||
{fbvElement type="checkbox" label="submission.submit.selectPrincipalContact" id="primaryContact" checked=$primaryContact}
|
||||
{fbvElement type="checkbox" label="submission.submit.includeInBrowse" id="includeInBrowse" checked=$includeInBrowse}
|
||||
{/fbvFormSection}
|
||||
{/fbvFormArea}
|
||||
|
||||
{if $submissionId}
|
||||
<input type="hidden" name="submissionId" value="{$submissionId|escape}" />
|
||||
{/if}
|
||||
{if $gridId}
|
||||
<input type="hidden" name="gridId" value="{$gridId|escape}" />
|
||||
{/if}
|
||||
{if $rowId}
|
||||
<input type="hidden" name="rowId" value="{$rowId|escape}" />
|
||||
{/if}
|
||||
|
||||
<p><span class="formRequired">{translate key="common.requiredField"}</span></p>
|
||||
{fbvFormButtons id="step2Buttons" submitText="common.save"}
|
||||
</form>
|
||||
67
email-patch/source/authorForm.tpl
Normal file
67
email-patch/source/authorForm.tpl
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{**
|
||||
* templates/controllers/grid/users/author/form/authorForm.tpl
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Submission Contributor grid form
|
||||
*
|
||||
*}
|
||||
|
||||
<script>
|
||||
$(function() {ldelim}
|
||||
$('#editAuthor').pkpHandler(
|
||||
'$.pkp.controllers.form.AjaxFormHandler'
|
||||
);
|
||||
{rdelim});
|
||||
</script>
|
||||
|
||||
<form class="pkp_form" id="editAuthor" method="post" action="{url op="updateAuthor" authorId=$authorId}">
|
||||
{csrf}
|
||||
{include file="controllers/notification/inPlaceNotification.tpl" notificationId="authorFormNotification"}
|
||||
|
||||
{include
|
||||
file="common/userDetails.tpl"
|
||||
disableUserNameSection=true
|
||||
disableAuthSourceSection=true
|
||||
disablePasswordSection=true
|
||||
disableSendNotifySection=true
|
||||
disableSalutationSection=true
|
||||
disableInitialsSection=true
|
||||
disablePhoneSection=true
|
||||
disableLocaleSection=true
|
||||
disableInterestsSection=true
|
||||
disableMailingSection=true
|
||||
disableSignatureSection=true
|
||||
extraContentSectionUnfolded=true
|
||||
countryRequired=true
|
||||
emailIsOptional=true
|
||||
}
|
||||
|
||||
{fbvFormArea id="submissionSpecific"}
|
||||
{fbvFormSection id="userGroupId" title="submission.submit.contributorRole" list=true required=true}
|
||||
{iterate from=authorUserGroups item=userGroup}
|
||||
{if $userGroupId == $userGroup->getId()}{assign var="checked" value=true}{else}{assign var="checked" value=false}{/if}
|
||||
{fbvElement type="radio" id="userGroup"|concat:$userGroup->getId() name="userGroupId" value=$userGroup->getId() checked=$checked label=$userGroup->getLocalizedName() translate=false}
|
||||
{/iterate}
|
||||
{/fbvFormSection}
|
||||
{fbvFormSection list="true"}
|
||||
{fbvElement type="checkbox" label="submission.submit.selectPrincipalContact" id="primaryContact" checked=$primaryContact}
|
||||
{fbvElement type="checkbox" label="submission.submit.includeInBrowse" id="includeInBrowse" checked=$includeInBrowse}
|
||||
{/fbvFormSection}
|
||||
{/fbvFormArea}
|
||||
|
||||
{if $submissionId}
|
||||
<input type="hidden" name="submissionId" value="{$submissionId|escape}" />
|
||||
{/if}
|
||||
{if $gridId}
|
||||
<input type="hidden" name="gridId" value="{$gridId|escape}" />
|
||||
{/if}
|
||||
{if $rowId}
|
||||
<input type="hidden" name="rowId" value="{$rowId|escape}" />
|
||||
{/if}
|
||||
|
||||
<p><span class="formRequired">{translate key="common.requiredField"}</span></p>
|
||||
{fbvFormButtons id="step2Buttons" submitText="common.save"}
|
||||
</form>
|
||||
188
email-patch/source/userDetails.old.tpl
Normal file
188
email-patch/source/userDetails.old.tpl
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
{**
|
||||
* templates/common/userDetails.tpl
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Common user details form.
|
||||
*
|
||||
* Parameters:
|
||||
* $disableUserNameSection: Disable UserName section
|
||||
* $disableEmailSection: Disable Email section
|
||||
* $disableAuthSourceSection: Disable Auth section
|
||||
* $disablePasswordSection: Disable Password section
|
||||
* $disableSendNotifySection: Disable SendNotify section
|
||||
* $disableSalutationSection: Disable Salutation section
|
||||
* $disableInitialsSection: Disable Initials section
|
||||
* $disablePhoneSection: Disable Phone section
|
||||
* $disableLocaleSection: Disable Locale section
|
||||
* $disableInterestsSection: Disable Interests section
|
||||
* $disableMailingSection: Disable Mailing section
|
||||
* $disableSignatureSection: Disable Signature section
|
||||
*
|
||||
* $countryRequired: Whether or not the country select is a required field
|
||||
* $extraContentSectionUnfolded: Whether or not the extra content section is unfolded by default
|
||||
*}
|
||||
|
||||
{fbvFormArea id="userDetails"}
|
||||
{fbvFormSection title="user.name"}
|
||||
{fbvElement type="text" label="user.firstName" required="true" id="firstName" value=$firstName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{fbvElement type="text" label="user.middleName" id="middleName" value=$middleName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{fbvElement type="text" label="user.lastName" required="true" id="lastName" value=$lastName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableUserNameSection}
|
||||
{if !$userId}{capture assign="usernameInstruction"}{translate key="user.register.usernameRestriction"}{/capture}{/if}
|
||||
{fbvFormSection for="username" description=$usernameInstruction translate=false}
|
||||
{if !$userId}
|
||||
{fbvElement type="text" label="user.username" id="username" required="true" value=$username maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{fbvElement type="button" label="common.suggest" id="suggestUsernameButton" inline=true class="default"}
|
||||
{else}
|
||||
{fbvFormSection title="user.username" suppressId="true"}
|
||||
{$username|escape}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableEmailSection}
|
||||
{fbvFormSection title="about.contact"}
|
||||
{fbvElement type="text" label="user.email" id="email" required="true" value=$email maxlength="90" size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableAuthSourceSection}
|
||||
{fbvFormSection title="grid.user.authSource" for="authId"}
|
||||
{fbvElement type="select" name="authId" id="authId" defaultLabel="" defaultValue="" from=$authSourceOptions translate="true" selected=$authId}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disablePasswordSection}
|
||||
{if $userId}{capture assign="passwordInstruction"}{translate key="user.profile.leavePasswordBlank"} {translate key="user.register.form.passwordLengthRestriction" length=$minPasswordLength}{/capture}{/if}
|
||||
{fbvFormArea id="passwordSection" title="user.password"}
|
||||
{fbvFormSection for="password" description=$passwordInstruction translate=false}
|
||||
{fbvElement type="text" label="user.password" required=$passwordRequired name="password" id="password" password="true" value=$password maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{fbvElement type="text" label="user.repeatPassword" required=$passwordRequired name="password2" id="password2" password="true" value=$password2 maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$userId}
|
||||
{fbvFormSection title="grid.user.generatePassword" for="generatePassword" list=true}
|
||||
{if $generatePassword}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="generatePassword" id="generatePassword" checked=$checked label="grid.user.generatePasswordDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{fbvFormSection title="grid.user.mustChangePassword" for="mustChangePassword" list=true}
|
||||
{if $mustChangePassword}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="mustChangePassword" id="mustChangePassword" checked=$checked label="grid.user.mustChangePasswordDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/fbvFormArea}
|
||||
{/if}
|
||||
|
||||
{if $countryRequired}
|
||||
{assign var="countryRequired" value=true}
|
||||
{else}
|
||||
{assign var="countryRequired" value=false}
|
||||
{/if}
|
||||
{fbvFormSection for="country" title="common.country"}
|
||||
{fbvElement type="select" label="common.country" name="country" id="country" required=$countryRequired defaultLabel="" defaultValue="" from=$countries selected=$country translate="0" size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableSendNotifySection}
|
||||
{fbvFormSection title="grid.user.notifyUser" for="sendNotify" list=true}
|
||||
{if $sendNotify}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="sendNotify" id="sendNotify" checked=$checked label="grid.user.notifyUserDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormArea}
|
||||
{call_hook name="Common::UserDetails::AdditionalItems"}
|
||||
{capture assign="extraContent"}
|
||||
{fbvFormArea id="userFormExtendedLeft"}
|
||||
{fbvFormSection}
|
||||
{if !$disableSalutationSection}
|
||||
{fbvElement type="text" label="user.salutation" name="salutation" id="salutation" value=$salutation maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{fbvElement type="text" label="user.suffix" id="suffix" value=$suffix size=$fbvStyles.size.SMALL inline=true}
|
||||
{if !$disableInitialsSection}
|
||||
{fbvElement type="text" label="user.initials" name="initials" id="initials" value=$initials maxlength="5" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
|
||||
{fbvFormSection}
|
||||
{fbvElement type="text" label="user.url" name="userUrl" id="userUrl" value=$userUrl maxlength="255" inline=true size=$fbvStyles.size.SMALL}
|
||||
{if !$disablePhoneSection}
|
||||
{fbvElement type="text" label="user.phone" name="phone" id="phone" value=$phone maxlength="24" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{fbvElement type="text" label="user.orcid" name="orcid" id="orcid" value=$orcid maxlength="37" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableLocaleSection && count($availableLocales) > 1}
|
||||
{fbvFormSection title="user.workingLanguages" list=true}
|
||||
{foreach from=$availableLocales key=localeKey item=localeName}
|
||||
{if $userLocales && in_array($localeKey, $userLocales)}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="userLocales[]" id="userLocales-$localeKey" value=$localeKey checked=$checked label=$localeName translate=false}
|
||||
{/foreach}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableInterestsSection}
|
||||
{fbvFormSection for="interests"}
|
||||
{fbvElement type="interests" id="interests" interests=$interests label="user.interests"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{fbvFormSection for="affiliation"}
|
||||
{fbvElement type="text" label="user.affiliation" multilingual="true" name="affiliation" id="affiliation" value=$affiliation inline=true size=$fbvStyles.size.LARGE}
|
||||
{/fbvFormSection}
|
||||
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="user.biography" multilingual="true" name="biography" id="biography" rich=true value=$biography}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableMailingSection}
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="common.mailingAddress" name="mailingAddress" id="mailingAddress" rich=true value=$mailingAddress}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableSignatureSection}
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="user.signature" multilingual="true" name="signature" id="signature" value=$signature rich=true}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormArea}
|
||||
{/capture}
|
||||
|
||||
{fbvFormSection}
|
||||
{if $extraContentSectionUnfolded}
|
||||
{fbvFormSection title="grid.user.userDetails"}
|
||||
{$extraContent}
|
||||
{/fbvFormSection}
|
||||
{else}
|
||||
<div id="userExtraFormFields" class="left full">
|
||||
{include file="controllers/extrasOnDemand.tpl"
|
||||
id="userExtras"
|
||||
widgetWrapper="#userExtraFormFields"
|
||||
moreDetailsText="grid.user.moreDetails"
|
||||
lessDetailsText="grid.user.lessDetails"
|
||||
extraContent=$extraContent
|
||||
}
|
||||
</div>
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
194
email-patch/source/userDetails.tpl
Normal file
194
email-patch/source/userDetails.tpl
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
{**
|
||||
* templates/common/userDetails.tpl
|
||||
*
|
||||
* Copyright (c) 2014-2018 Simon Fraser University
|
||||
* Copyright (c) 2003-2018 John Willinsky
|
||||
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Common user details form.
|
||||
*
|
||||
* Parameters:
|
||||
* $disableUserNameSection: Disable UserName section
|
||||
* $disableEmailSection: Disable Email section
|
||||
* $disableAuthSourceSection: Disable Auth section
|
||||
* $disablePasswordSection: Disable Password section
|
||||
* $disableSendNotifySection: Disable SendNotify section
|
||||
* $disableSalutationSection: Disable Salutation section
|
||||
* $disableInitialsSection: Disable Initials section
|
||||
* $disablePhoneSection: Disable Phone section
|
||||
* $disableLocaleSection: Disable Locale section
|
||||
* $disableInterestsSection: Disable Interests section
|
||||
* $disableMailingSection: Disable Mailing section
|
||||
* $disableSignatureSection: Disable Signature section
|
||||
*
|
||||
* $countryRequired: Whether or not the country select is a required field
|
||||
* $extraContentSectionUnfolded: Whether or not the extra content section is unfolded by default
|
||||
*}
|
||||
|
||||
{fbvFormArea id="userDetails"}
|
||||
{fbvFormSection title="user.name"}
|
||||
{fbvElement type="text" label="user.firstName" required="true" id="firstName" value=$firstName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{fbvElement type="text" label="user.middleName" id="middleName" value=$middleName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{fbvElement type="text" label="user.lastName" required="true" id="lastName" value=$lastName maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableUserNameSection}
|
||||
{if !$userId}{capture assign="usernameInstruction"}{translate key="user.register.usernameRestriction"}{/capture}{/if}
|
||||
{fbvFormSection for="username" description=$usernameInstruction translate=false}
|
||||
{if !$userId}
|
||||
{fbvElement type="text" label="user.username" id="username" required="true" value=$username maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{fbvElement type="button" label="common.suggest" id="suggestUsernameButton" inline=true class="default"}
|
||||
{else}
|
||||
{fbvFormSection title="user.username" suppressId="true"}
|
||||
{$username|escape}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableEmailSection}
|
||||
{if $emailIsOptional}
|
||||
{assign var="emailRequired" value=false}
|
||||
{else}
|
||||
{assign var="emailRequired" value=true}
|
||||
{/if}
|
||||
|
||||
{fbvFormSection title="about.contact"}
|
||||
{fbvElement type="text" label="user.email" id="email" required=$emailRequired value=$email maxlength="90" size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableAuthSourceSection}
|
||||
{fbvFormSection title="grid.user.authSource" for="authId"}
|
||||
{fbvElement type="select" name="authId" id="authId" defaultLabel="" defaultValue="" from=$authSourceOptions translate="true" selected=$authId}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disablePasswordSection}
|
||||
{if $userId}{capture assign="passwordInstruction"}{translate key="user.profile.leavePasswordBlank"} {translate key="user.register.form.passwordLengthRestriction" length=$minPasswordLength}{/capture}{/if}
|
||||
{fbvFormArea id="passwordSection" title="user.password"}
|
||||
{fbvFormSection for="password" description=$passwordInstruction translate=false}
|
||||
{fbvElement type="text" label="user.password" required=$passwordRequired name="password" id="password" password="true" value=$password maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{fbvElement type="text" label="user.repeatPassword" required=$passwordRequired name="password2" id="password2" password="true" value=$password2 maxlength="32" inline=true size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$userId}
|
||||
{fbvFormSection title="grid.user.generatePassword" for="generatePassword" list=true}
|
||||
{if $generatePassword}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="generatePassword" id="generatePassword" checked=$checked label="grid.user.generatePasswordDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{fbvFormSection title="grid.user.mustChangePassword" for="mustChangePassword" list=true}
|
||||
{if $mustChangePassword}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="mustChangePassword" id="mustChangePassword" checked=$checked label="grid.user.mustChangePasswordDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/fbvFormArea}
|
||||
{/if}
|
||||
|
||||
{if $countryRequired}
|
||||
{assign var="countryRequired" value=true}
|
||||
{else}
|
||||
{assign var="countryRequired" value=false}
|
||||
{/if}
|
||||
{fbvFormSection for="country" title="common.country"}
|
||||
{fbvElement type="select" label="common.country" name="country" id="country" required=$countryRequired defaultLabel="" defaultValue="" from=$countries selected=$country translate="0" size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableSendNotifySection}
|
||||
{fbvFormSection title="grid.user.notifyUser" for="sendNotify" list=true}
|
||||
{if $sendNotify}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="sendNotify" id="sendNotify" checked=$checked label="grid.user.notifyUserDescription" translate="true"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormArea}
|
||||
{call_hook name="Common::UserDetails::AdditionalItems"}
|
||||
{capture assign="extraContent"}
|
||||
{fbvFormArea id="userFormExtendedLeft"}
|
||||
{fbvFormSection}
|
||||
{if !$disableSalutationSection}
|
||||
{fbvElement type="text" label="user.salutation" name="salutation" id="salutation" value=$salutation maxlength="40" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{fbvElement type="text" label="user.suffix" id="suffix" value=$suffix size=$fbvStyles.size.SMALL inline=true}
|
||||
{if !$disableInitialsSection}
|
||||
{fbvElement type="text" label="user.initials" name="initials" id="initials" value=$initials maxlength="5" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
|
||||
{fbvFormSection}
|
||||
{fbvElement type="text" label="user.url" name="userUrl" id="userUrl" value=$userUrl maxlength="255" inline=true size=$fbvStyles.size.SMALL}
|
||||
{if !$disablePhoneSection}
|
||||
{fbvElement type="text" label="user.phone" name="phone" id="phone" value=$phone maxlength="24" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/if}
|
||||
{fbvElement type="text" label="user.orcid" name="orcid" id="orcid" value=$orcid maxlength="37" inline=true size=$fbvStyles.size.SMALL}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableLocaleSection && count($availableLocales) > 1}
|
||||
{fbvFormSection title="user.workingLanguages" list=true}
|
||||
{foreach from=$availableLocales key=localeKey item=localeName}
|
||||
{if $userLocales && in_array($localeKey, $userLocales)}
|
||||
{assign var="checked" value=true}
|
||||
{else}
|
||||
{assign var="checked" value=false}
|
||||
{/if}
|
||||
{fbvElement type="checkbox" name="userLocales[]" id="userLocales-$localeKey" value=$localeKey checked=$checked label=$localeName translate=false}
|
||||
{/foreach}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableInterestsSection}
|
||||
{fbvFormSection for="interests"}
|
||||
{fbvElement type="interests" id="interests" interests=$interests label="user.interests"}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{fbvFormSection for="affiliation"}
|
||||
{fbvElement type="text" label="user.affiliation" multilingual="true" name="affiliation" id="affiliation" value=$affiliation inline=true size=$fbvStyles.size.LARGE}
|
||||
{/fbvFormSection}
|
||||
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="user.biography" multilingual="true" name="biography" id="biography" rich=true value=$biography}
|
||||
{/fbvFormSection}
|
||||
|
||||
{if !$disableMailingSection}
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="common.mailingAddress" name="mailingAddress" id="mailingAddress" rich=true value=$mailingAddress}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
{if !$disableSignatureSection}
|
||||
{fbvFormSection}
|
||||
{fbvElement type="textarea" label="user.signature" multilingual="true" name="signature" id="signature" value=$signature rich=true}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
{/fbvFormArea}
|
||||
{/capture}
|
||||
|
||||
{fbvFormSection}
|
||||
{if $extraContentSectionUnfolded}
|
||||
{fbvFormSection title="grid.user.userDetails"}
|
||||
{$extraContent}
|
||||
{/fbvFormSection}
|
||||
{else}
|
||||
<div id="userExtraFormFields" class="left full">
|
||||
{include file="controllers/extrasOnDemand.tpl"
|
||||
id="userExtras"
|
||||
widgetWrapper="#userExtraFormFields"
|
||||
moreDetailsText="grid.user.moreDetails"
|
||||
lessDetailsText="grid.user.lessDetails"
|
||||
extraContent=$extraContent
|
||||
}
|
||||
</div>
|
||||
{/if}
|
||||
{/fbvFormSection}
|
||||
18
email-patch/userDetails.patch
Normal file
18
email-patch/userDetails.patch
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
--- userDetails_old.tpl 2019-03-13 05:30:51.480000000 +0300
|
||||
+++ userDetails.tpl 2019-03-13 05:30:51.479000000 +0300
|
||||
@@ -47,8 +47,14 @@
|
||||
{/if}
|
||||
|
||||
{if !$disableEmailSection}
|
||||
+ {if $emailIsOptional}
|
||||
+ {assign var="emailRequired" value=false}
|
||||
+ {else}
|
||||
+ {assign var="emailRequired" value=true}
|
||||
+ {/if}
|
||||
+
|
||||
{fbvFormSection title="about.contact"}
|
||||
- {fbvElement type="text" label="user.email" id="email" required="true" value=$email maxlength="90" size=$fbvStyles.size.MEDIUM}
|
||||
+ {fbvElement type="text" label="user.email" id="email" required=$emailRequired value=$email maxlength="90" size=$fbvStyles.size.MEDIUM}
|
||||
{/fbvFormSection}
|
||||
{/if}
|
||||
|
||||
1436
package-lock.json
generated
Normal file
1436
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
package.json
Normal file
33
package.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "gpmu-ojs-import",
|
||||
"version": "1.0.0",
|
||||
"description": "gpmu-ojs-import-js",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "DEBUG=* node src/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://fortunereject@bitbucket.org/fortunereject/gpmu-ojs-import-js.git"
|
||||
},
|
||||
"author": "Phil Zhitnikov",
|
||||
"license": "ISC",
|
||||
"homepage": "https://bitbucket.org/fortunereject/gpmu-ojs-import-js#readme",
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"glob": "^7.1.3",
|
||||
"inquirer": "^6.2.2",
|
||||
"manakin": "^0.5.2",
|
||||
"minimist": "^1.2.0",
|
||||
"qs": "^6.6.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.4",
|
||||
"schm": "^0.4.1",
|
||||
"schm-translate": "^0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^5.15.1"
|
||||
}
|
||||
}
|
||||
3
src/UPLOAD_ISSUES.bat
Normal file
3
src/UPLOAD_ISSUES.bat
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
cd /d "%~dp0"
|
||||
node index.js %*
|
||||
pause
|
||||
5
src/helpers.js
Normal file
5
src/helpers.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
exports.asyncForEach = async function (array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
}
|
||||
227
src/importer.js
Normal file
227
src/importer.js
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const inquirer = require("inquirer");
|
||||
const glob = require("glob");
|
||||
const cheerio = require("cheerio");
|
||||
|
||||
const Journal = require("./ojs/journal");
|
||||
const Issue = require("./ojs/issue");
|
||||
const Submission = require("./ojs/submission");
|
||||
const helpers = require("./helpers");
|
||||
|
||||
class Importer {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.submission = new Submission(client);
|
||||
|
||||
this.$ = cheerio.load("", { xmlMode: true });
|
||||
}
|
||||
|
||||
async chooseJournal(journalChoices) {
|
||||
journalChoices.push(new inquirer.Separator(), "[New journal]");
|
||||
|
||||
const questions = [
|
||||
{
|
||||
type: "list",
|
||||
name: "selectedJournal",
|
||||
message: "Choose journal to upload issue to",
|
||||
choices: journalChoices
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "selectedJournal",
|
||||
message: "Enter english slug for journal",
|
||||
when: answers => {
|
||||
return answers.selectedJournal == "[New journal]";
|
||||
},
|
||||
validate: function(value) {
|
||||
if (!value.match(/^[a-zA-Z0-9\/._-]+$/))
|
||||
return "Slug can only contain numbers, english letters, dashes (-) and underscores (_)";
|
||||
else if (journalChoices.includes(value))
|
||||
return "Slug exists. Choose another slug";
|
||||
else return true;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return await inquirer.prompt(questions).then(answers => {
|
||||
return answers.selectedJournal;
|
||||
});
|
||||
}
|
||||
|
||||
getXMLDatastores(paths) {
|
||||
const arr = paths.map(p => {
|
||||
p = path.resolve(p);
|
||||
const searchPattern = `${p}\\**\\*.xml`;
|
||||
return glob.sync(searchPattern);
|
||||
});
|
||||
|
||||
const flattenArr = arr.reduce((acc, val) => acc.concat(val), []);
|
||||
return flattenArr.filter((x, i, a) => a.indexOf(x) == i); // filter unique paths
|
||||
}
|
||||
|
||||
async importIssue(xmlFilePath, journalSlug) {
|
||||
const cwd = path.dirname(xmlFilePath);
|
||||
console.success("Processing directory:", path.relative(__dirname, cwd));
|
||||
|
||||
const xmlData = fs.readFileSync(xmlFilePath, "utf-16le");
|
||||
const $xml = cheerio.load(xmlData, { xmlMode: true });
|
||||
|
||||
// Create journal if needed
|
||||
const exists = await this.client.journalExists(journalSlug);
|
||||
if (!exists) {
|
||||
// console.error(`Journal with slug ${journalSlug} doesnt exist`);
|
||||
|
||||
const journalTitle_rus = $xml("journalInfo[lang=RUS]")
|
||||
.find("title")
|
||||
.text();
|
||||
const journalTitle_eng = $xml("journalInfo[lang=ENG]")
|
||||
.find("title")
|
||||
.text();
|
||||
|
||||
const journalInfo = {
|
||||
name: { rus: journalTitle_rus, eng: journalTitle_eng },
|
||||
path: journalSlug
|
||||
};
|
||||
// console.log("journalInfo", journalInfo);
|
||||
await Journal.create(this.client, journalInfo);
|
||||
}
|
||||
|
||||
//Collect issue info
|
||||
const $issue = $xml("issue");
|
||||
|
||||
const volume = $issue.children("volume").text();
|
||||
const number = $issue.children("number").text();
|
||||
const year = $issue
|
||||
.children("dateUni")
|
||||
.text()
|
||||
.slice(0, 4); //dirty hack for parameters like '201733/2017' or '201733'
|
||||
const title_rus = $issue.children("issTitle").text();
|
||||
|
||||
var info = {
|
||||
volume: volume,
|
||||
number: number,
|
||||
year: year,
|
||||
"title[ru_RU]": title_rus
|
||||
};
|
||||
|
||||
if (!title_rus) info["showTitle"] = "0";
|
||||
|
||||
if (!volume) info["showVolume"] = "0";
|
||||
|
||||
if (!number) info["showNumber"] = "0";
|
||||
|
||||
if (!year) info["showYear"] = "0";
|
||||
|
||||
// console.log(info)
|
||||
|
||||
const issueId = await Issue.create(this.client, journalSlug, info);
|
||||
console.success("Got issue id:", issueId);
|
||||
|
||||
// Process articles
|
||||
const $articles = $xml("article");
|
||||
const totalArticles = $articles.length;
|
||||
console.info(`Found ${totalArticles} articles`);
|
||||
|
||||
await helpers.asyncForEach($articles, async (articleXML, i) => {
|
||||
console.info(
|
||||
`Creating submission ${i + 1}/${totalArticles} with issueId ${issueId}`
|
||||
);
|
||||
var submissionInfo = await this.getArticleInfo(articleXML, cwd);
|
||||
|
||||
submissionInfo["issueId"] = issueId;
|
||||
|
||||
// TODO validate info
|
||||
// TODO validate file
|
||||
|
||||
await this.submission.create(journalSlug, submissionInfo);
|
||||
});
|
||||
|
||||
await Issue.publish(this.client, journalSlug, issueId);
|
||||
}
|
||||
|
||||
getAuthorInfo($individInfo) {
|
||||
var info = {};
|
||||
|
||||
const initials = $individInfo.find("initials").text();
|
||||
const splitted_initials = initials.split(/[\s.]+/).filter(Boolean);
|
||||
// console.log(initials, '||', splitted_initials);
|
||||
|
||||
const first_name = splitted_initials[0];
|
||||
info["firstName"] = first_name;
|
||||
|
||||
const middle_name =
|
||||
splitted_initials.length > 1 ? splitted_initials[1] : "";
|
||||
info["middleName"] = middle_name;
|
||||
|
||||
const surname = $individInfo.find("surname").text();
|
||||
info["lastName"] = surname;
|
||||
|
||||
const organization = $individInfo.find("orgName").text();
|
||||
const address = $individInfo.find("address").text();
|
||||
info["affiliation[ru_RU]"] = organization + " " + address;
|
||||
|
||||
const bio = $individInfo.find("otherInfo").text();
|
||||
info["biography[ru_RU]"] = bio;
|
||||
|
||||
const email = $individInfo.find("email").text();
|
||||
info["email"] = email;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
async getArticleInfo(articleXML, cwd) {
|
||||
const $article = this.$(articleXML);
|
||||
|
||||
const title_rus = $article.find("artTitle[lang=RUS]").text();
|
||||
const title_eng = $article.find("artTitle[lang=ENG]").text();
|
||||
|
||||
const abstract_rus = $article.find("abstract[lang=RUS]").text() || "<br>";
|
||||
const abstract_eng = $article.find("abstract[lang=ENG]").text() || "<br>";
|
||||
|
||||
const pages = $article.find("pages").text();
|
||||
|
||||
const materialFileName = $article.find("file").text();
|
||||
const materialPath = path.join(cwd, materialFileName);
|
||||
|
||||
const $keywords = $article.find("keyword");
|
||||
|
||||
var keywords = [];
|
||||
$keywords.each((i, k) => {
|
||||
const keyword = this.$(k).text();
|
||||
keywords.push(keyword);
|
||||
});
|
||||
|
||||
// Collect authors
|
||||
const $authors = $article.find("author");
|
||||
|
||||
var authorInfoCollection = [];
|
||||
$authors.each((i, author) => {
|
||||
const $author = this.$(author);
|
||||
const $individInfo_rus = $author.find("individInfo[lang=RUS]");
|
||||
const $individInfo_eng = $author.find("individInfo[lang=ENG]");
|
||||
|
||||
const authorInfo = this.getAuthorInfo($individInfo_rus);
|
||||
authorInfoCollection.push(authorInfo);
|
||||
});
|
||||
|
||||
// console.log(title_rus)
|
||||
// console.log(title_eng)
|
||||
// console.log(abstract_rus)
|
||||
// console.log(keywords);
|
||||
|
||||
return {
|
||||
title_rus: title_rus,
|
||||
title_eng: title_eng,
|
||||
abstract_rus: abstract_rus,
|
||||
abstract_eng: abstract_eng,
|
||||
keywords: keywords,
|
||||
pages: pages,
|
||||
materialFilePath: materialPath,
|
||||
authors: authorInfoCollection
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Importer;
|
||||
34
src/index.js
Normal file
34
src/index.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
var argv = require("minimist")(process.argv.slice(2));
|
||||
|
||||
require("manakin").global;
|
||||
const inquirer = require("inquirer");
|
||||
|
||||
const Client = require("./ojs/client");
|
||||
const Importer = require("./importer");
|
||||
const config = require("./config");
|
||||
const helpers = require("./helpers");
|
||||
|
||||
const client = new Client(config.PRODUCTION);
|
||||
const importer = new Importer(client);
|
||||
|
||||
if (!argv._) {
|
||||
console.error("No dirs provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const separateUpload = argv.separate || false;
|
||||
|
||||
const datastores = importer.getXMLDatastores(argv._);
|
||||
console.log("Got datastores:", datastores);
|
||||
|
||||
(async () => {
|
||||
await importer.client.init();
|
||||
await helpers.asyncForEach(datastores, async (d, i) => {
|
||||
if (separateUpload || i == 0) {
|
||||
const journals = await importer.client.getJournals();
|
||||
selectedJournal = await importer.chooseJournal(journals);
|
||||
}
|
||||
|
||||
await importer.importIssue(d, selectedJournal);
|
||||
});
|
||||
})();
|
||||
186
src/ojs/client.js
Normal file
186
src/ojs/client.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
const rp = require("request-promise");
|
||||
const cheerio = require("cheerio");
|
||||
const url = require("url");
|
||||
|
||||
const endpoints = require("./endpoints");
|
||||
|
||||
class Client {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
|
||||
this.host = config.host;
|
||||
this.csrfToken = "";
|
||||
|
||||
this.apiDefaults = {
|
||||
baseUrl: this.host,
|
||||
jar: true, // enable cookies
|
||||
gzip: this.config.gzip || false,
|
||||
resolveWithFullResponse: true,
|
||||
headers: {
|
||||
// 'Host': '127.0.0.1:8080',
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0",
|
||||
Accept: "application/json, text/javascript, */*; q=0.01",
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
Connection: "keep-alive",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
}
|
||||
};
|
||||
|
||||
this.api = rp.defaults(this.apiDefaults);
|
||||
}
|
||||
|
||||
init() {
|
||||
return this.getCSRF()
|
||||
.then(token => (this.csrfToken = token))
|
||||
.then(() =>
|
||||
this.authorize(this.config.adminUsername, this.config.adminPassword)
|
||||
)
|
||||
.catch(err => console.error("Client init failed:", err));
|
||||
}
|
||||
|
||||
getCSRF() {
|
||||
// console.log("getting CSRF token..");
|
||||
|
||||
return this.api
|
||||
.get(endpoints.login.page)
|
||||
.then(response => {
|
||||
const $ = cheerio.load(response.body);
|
||||
const csrfToken = $("input[name=csrfToken]").val();
|
||||
|
||||
return csrfToken;
|
||||
})
|
||||
.catch(err => console.error("CSRF fetching failed:", err));
|
||||
}
|
||||
|
||||
authorize(user, password) {
|
||||
console.log("authorizing..");
|
||||
|
||||
return this.api
|
||||
.post(endpoints.login.action, {
|
||||
form: {
|
||||
username: user,
|
||||
password: password,
|
||||
remember: "1"
|
||||
},
|
||||
simple: false // because server responds with 302 code
|
||||
})
|
||||
.then(response => {
|
||||
// TODO check login success
|
||||
console.success("authorized");
|
||||
|
||||
// Add cookie to headers
|
||||
var cookie = response.headers["set-cookie"].toString();
|
||||
this.api.defaults({ headers: { Cookie: cookie } });
|
||||
})
|
||||
.catch(err => console.error("Login failed:", err));
|
||||
}
|
||||
|
||||
send(options) {
|
||||
if (options.method == "POST" && !options.formData) {
|
||||
options.form = options.form || {};
|
||||
options.form["csrfToken"] = this.csrfToken;
|
||||
}
|
||||
return this.api(options);
|
||||
}
|
||||
|
||||
sendJson(options) {
|
||||
options["json"] = true;
|
||||
options["resolveWithFullResponse"] = false;
|
||||
|
||||
return this.send(options);
|
||||
}
|
||||
|
||||
getJournals() {
|
||||
// this.restoreBaseUrl();
|
||||
|
||||
return this.send({
|
||||
baseUrl: this.host,
|
||||
method: "GET",
|
||||
uri: endpoints.journal.getAll,
|
||||
|
||||
json: true,
|
||||
resolveWithFullResponse: false
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
console.log("Parsing journals..");
|
||||
var journals = [];
|
||||
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const $labels = $(".gridRow td:not(.first_column) .label");
|
||||
|
||||
$labels.each((i, el) => {
|
||||
const name = $(el)
|
||||
.text()
|
||||
.trim();
|
||||
journals.push(name);
|
||||
});
|
||||
|
||||
return journals;
|
||||
})
|
||||
.catch(err => console.error("Fetching journals failed:", err));
|
||||
}
|
||||
|
||||
// TODO clean this mess
|
||||
getJournalUrl(journalSlug) {
|
||||
return url.resolve(this.host, journalSlug);
|
||||
}
|
||||
|
||||
setJournalUrl(journalSlug) {
|
||||
// console.log('setting slug:', journalSlug);
|
||||
this.apiDefaults.baseUrl = this.getJournalUrl(journalSlug);
|
||||
this.api.defaults(this.apiDefaults);
|
||||
}
|
||||
|
||||
// restoreBaseUrl() {
|
||||
// this.apiDefaults.baseUrl = this.host;
|
||||
// this.api.defaults(this.apiDefaults)
|
||||
// }
|
||||
|
||||
async journalExists(slug) {
|
||||
return await this.getJournals().then(journals => {
|
||||
return journals.includes(slug);
|
||||
});
|
||||
}
|
||||
|
||||
getIssueIds(journalSlug) {
|
||||
//TODO check journal exists
|
||||
|
||||
const journalUrl = this.getJournalUrl(journalSlug);
|
||||
|
||||
return this.send({
|
||||
baseUrl: journalUrl,
|
||||
method: "GET",
|
||||
uri: endpoints.issue.getAll,
|
||||
|
||||
json: true,
|
||||
resolveWithFullResponse: false
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const $gridRows = $(".gridRow"); // <tr id="component-grid-issues-futureissuegrid-row-1" class="gridRow has_extras"></tr>
|
||||
|
||||
var ids = [];
|
||||
|
||||
$gridRows.each((i, el) => {
|
||||
const idAttr = $(el).attr("id"); // component-grid-issues-futureissuegrid-row-1
|
||||
const id = idAttr.split("-").slice(-1)[0]; // 1
|
||||
ids.push(id);
|
||||
});
|
||||
|
||||
return ids;
|
||||
})
|
||||
.catch(err => console.error("getIssueIds failed:", err));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
||||
36
src/ojs/endpoints.js
Normal file
36
src/ojs/endpoints.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
module.exports = {
|
||||
login: {
|
||||
page: '/index/login',
|
||||
action: '/index/login/signIn'
|
||||
},
|
||||
journal: {
|
||||
getAll: 'index/$$$call$$$/grid/admin/journal/journal-grid/fetch-grid',
|
||||
create: 'index/$$$call$$$/grid/admin/journal/journal-grid/update-context'
|
||||
},
|
||||
issue: {
|
||||
getAll: '$$$call$$$/grid/issues/future-issue-grid/fetch-grid',
|
||||
create: '$$$call$$$/grid/issues/future-issue-grid/update-issue?issueId=',
|
||||
publish: '$$$call$$$/grid/issues/future-issue-grid/publish-issue'
|
||||
},
|
||||
submission: {
|
||||
prepare: 'submission/step/1',
|
||||
step1_save: 'submission/saveStep/1',
|
||||
step2: {
|
||||
getGenreId: '$$$call$$$/wizard/file-upload/file-upload-wizard/display-file-upload-form',
|
||||
save: 'submission/saveStep/2'
|
||||
},
|
||||
step3_metadata: 'submission/saveStep/3',
|
||||
step4_confirm: 'submission/saveStep/4',
|
||||
galley: {
|
||||
create: '$$$call$$$/grid/article-galleys/article-galley-grid/update-galley',
|
||||
getAssocTypeAssocId: '$$$call$$$/grid/article-galleys/article-galley-grid/fetch-row'
|
||||
},
|
||||
getAuthors: '$$$call$$$/grid/users/author/author-grid/fetch-grid',
|
||||
removeAuthor: '$$$call$$$/grid/users/author/author-grid/delete-author',
|
||||
authorForm: '$$$call$$$/grid/users/author/author-grid/add-author',
|
||||
addAuthor: '$$$call$$$/grid/users/author/author-grid/update-author?authorId=',
|
||||
uploadFile: '$$$call$$$/wizard/file-upload/file-upload-wizard/upload-file',
|
||||
|
||||
save: '$$$call$$$/tab/issue-entry/issue-entry-tab/save-publication-metadata-form'
|
||||
},
|
||||
}
|
||||
124
src/ojs/form-data.js
Normal file
124
src/ojs/form-data.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
module.exports = {
|
||||
submission: {
|
||||
step1_save: {
|
||||
'csrfToken': '',
|
||||
'sectionId': '14',
|
||||
'userGroupId': '240',
|
||||
|
||||
'submissionChecklist': '1',
|
||||
'locale': 'ru_RU',
|
||||
'checklist-0': '1',
|
||||
'checklist-1': '1',
|
||||
'checklist-2': '1',
|
||||
'checklist-3': '1',
|
||||
'checklist-4': '1',
|
||||
'commentsToEditor': '',
|
||||
'privacyConsent': '1',
|
||||
},
|
||||
|
||||
step2: {
|
||||
getGenreId: {
|
||||
'submissionId': '',
|
||||
|
||||
'stageId': '1',
|
||||
'fileStage': '2',
|
||||
},
|
||||
uploadQuery: {
|
||||
'csrfToken': '',
|
||||
'submissionId': '',
|
||||
|
||||
'stageId': '1',
|
||||
'fileStage': '2',
|
||||
'reviewRoundId': '',
|
||||
'assocType': '',
|
||||
'assocId': ''
|
||||
}
|
||||
},
|
||||
|
||||
step3_metadata: {
|
||||
'csrfToken': '',
|
||||
|
||||
'prefix[ru_RU]': '',
|
||||
'subtitle[ru_RU]': '',
|
||||
'title[ru_RU]': 'testing',
|
||||
'abstract[ru_RU]': 'testing',
|
||||
'keywords[ru_RU-keywords]': ['lulz', 'testtest2']
|
||||
},
|
||||
|
||||
galley: {
|
||||
create: {
|
||||
'csrfToken': '',
|
||||
|
||||
'label': 'PDF',
|
||||
'galleyLocale': 'ru_RU',
|
||||
'remoteURL': ''
|
||||
},
|
||||
uploadQuery: {
|
||||
'csrfToken': '',
|
||||
'submissionId': '',
|
||||
|
||||
'stageId': '5',
|
||||
'fileStage': '10',
|
||||
'reviewRoundId': '',
|
||||
'assocType': '',
|
||||
'assocId': ''
|
||||
}
|
||||
},
|
||||
|
||||
addAuthor: {
|
||||
'csrfToken': '',
|
||||
'submissionId': '',
|
||||
|
||||
'firstName': 'Иван',
|
||||
'middleName': '',
|
||||
'lastName': 'Иванов',
|
||||
'email': '',
|
||||
'country': 'RU',
|
||||
'suffix': '',
|
||||
'userUrl': '',
|
||||
'orcid': '',
|
||||
'affiliation[ru_RU]': 'org',
|
||||
'biography[ru_RU]': '',
|
||||
'userGroupId': '',
|
||||
'includeInBrowse': 'on',
|
||||
},
|
||||
|
||||
save: {
|
||||
'csrfToken': '',
|
||||
'submissionId': '',
|
||||
|
||||
'issueId': '',
|
||||
'stageId': '5',
|
||||
'copyrightHolder[ru_RU]': 'test-journal',
|
||||
'pages': '',
|
||||
'waivePublicationFee': '0',
|
||||
'markAsPaid': 0,
|
||||
'licenseURL': '',
|
||||
'copyrightYear': '',
|
||||
}
|
||||
},
|
||||
|
||||
issue: {
|
||||
create: {
|
||||
'csrfToken': '',
|
||||
|
||||
'title[ru_RU]': 'issue-title',
|
||||
'volume': '1',
|
||||
'number': '1',
|
||||
'year': '2019',
|
||||
'showVolume': '1',
|
||||
'showNumber': '1',
|
||||
'showYear': '1',
|
||||
'showTitle': '1',
|
||||
'description[ru_RU]': '',
|
||||
'temporaryFileId': ''
|
||||
},
|
||||
|
||||
publish: {
|
||||
'csrfToken': '',
|
||||
|
||||
'issueId': '',
|
||||
'confirmed': 'true',
|
||||
}
|
||||
}
|
||||
}
|
||||
56
src/ojs/issue.js
Normal file
56
src/ojs/issue.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const endpoints = require('./endpoints')
|
||||
const form_data = require('./form-data')
|
||||
|
||||
diff = (a, b) => a.filter(function (i) { return b.indexOf(i) < 0; })
|
||||
|
||||
exports.create = async (client, journalSlug, info = {}) => {
|
||||
const journalUrl = client.getJournalUrl(journalSlug);
|
||||
|
||||
const issueIdsBefore = await client.getIssueIds(journalSlug);
|
||||
|
||||
// Create issue
|
||||
await client
|
||||
.sendJson({
|
||||
baseUrl: journalUrl,
|
||||
method: 'POST',
|
||||
uri: endpoints.issue.create,
|
||||
form: {
|
||||
...form_data.issue.create,
|
||||
...info
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
if (!jsonData)
|
||||
Promise.reject('Wrong response');
|
||||
|
||||
console.info('Create issue result:', jsonData);
|
||||
})
|
||||
.catch(err => console.error('Issue creation failed:', err))
|
||||
|
||||
const issueIdsAfter = await client.getIssueIds(journalSlug);
|
||||
|
||||
return diff(issueIdsAfter, issueIdsBefore)[0]
|
||||
}
|
||||
|
||||
exports.publish = async (client, journalSlug, issueId) => {
|
||||
const journalUrl = client.getJournalUrl(journalSlug);
|
||||
|
||||
return client
|
||||
.sendJson({
|
||||
baseUrl: journalUrl,
|
||||
method: 'POST',
|
||||
uri: endpoints.issue.publish,
|
||||
form: {
|
||||
...form_data.issue.publish,
|
||||
issueId: issueId,
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info('Issue.publish result:', jsonData);
|
||||
|
||||
if (!jsonData)
|
||||
Promise.reject();
|
||||
})
|
||||
.catch(err => console.error('Issue publishing failed:', err))
|
||||
}
|
||||
83
src/ojs/journal.js
Normal file
83
src/ojs/journal.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
const schema = require("schm");
|
||||
const translate = require("schm-translate");
|
||||
|
||||
const endpoints = require("./endpoints");
|
||||
|
||||
const journalCreateSchema = schema(
|
||||
{
|
||||
"name[ru_RU]": {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
"name[en_US]": String,
|
||||
"description[ru_RU]": String,
|
||||
"description[en_US]": String,
|
||||
path: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
enabled: 1
|
||||
},
|
||||
translate({
|
||||
"name[ru_RU]": "name.rus",
|
||||
"name[en_US]": "name.eng",
|
||||
"description[ru_RU]": "description.rus",
|
||||
"description[en_US]": "description.eng",
|
||||
path: "path",
|
||||
enabled: "enabled"
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
@param journalInfo:
|
||||
|
||||
{
|
||||
name: {rus: 'лала', eng: 'lala'},
|
||||
description: {rus: 'лала', eng: 'lala'},
|
||||
path: 'test-journal',
|
||||
[enabled: 0]
|
||||
}
|
||||
**/
|
||||
exports.create = async (client, journalInfo = {}) => {
|
||||
await journalCreateSchema
|
||||
.validate(journalInfo)
|
||||
.then(async parsedData => {
|
||||
// console.log('Parsed schema:', parsedData)
|
||||
|
||||
await client
|
||||
.send({
|
||||
method: "POST",
|
||||
uri: endpoints.journal.create,
|
||||
form: parsedData
|
||||
})
|
||||
.then(response => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("Journal creation result:", response.body);
|
||||
})
|
||||
.catch(err => console.error("Journal creation failed:", err));
|
||||
})
|
||||
.catch(err => console.error("Journal info validation failed", err));
|
||||
};
|
||||
|
||||
exports.create_no_validation = async (client, journalInfo = {}) => {
|
||||
const info = {
|
||||
"name[ru_RU]": journalInfo.name.rus || "",
|
||||
"name[en_US]": journalInfo.name.eng || "",
|
||||
"description[ru_RU]": "",
|
||||
"description[en_US]": "",
|
||||
path: journalInfo.path,
|
||||
enabled: journalInfo.enabled || 1
|
||||
};
|
||||
|
||||
return await client
|
||||
.send({
|
||||
method: "POST",
|
||||
uri: endpoints.journal.create,
|
||||
form: info
|
||||
})
|
||||
.then(response => {
|
||||
// TODO Check JSON has certain info
|
||||
console.log(response.body);
|
||||
})
|
||||
.catch(err => console.error("Journal creation failed:", err));
|
||||
};
|
||||
452
src/ojs/submission.js
Normal file
452
src/ojs/submission.js
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
const url = require("url");
|
||||
|
||||
const cheerio = require("cheerio");
|
||||
|
||||
const helpers = require("../helpers");
|
||||
const endpoints = require("./endpoints");
|
||||
const form_data = require("./form-data");
|
||||
|
||||
class Submission {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.submissionId = 1;
|
||||
|
||||
this.info;
|
||||
}
|
||||
|
||||
prepare() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "GET",
|
||||
uri: endpoints.submission.prepare
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const userGroupEl = $("input[id^='userGroup']").first();
|
||||
const sectionIdEl = $("#sectionId");
|
||||
|
||||
const result = {
|
||||
userGroupId: userGroupEl.val(),
|
||||
sectionId: sectionIdEl.val()
|
||||
};
|
||||
|
||||
console.info(result);
|
||||
|
||||
return result;
|
||||
})
|
||||
.catch(err =>
|
||||
console.error(
|
||||
"Prepare submission (userGroupId and sectionId fetching) failed:",
|
||||
err
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
step1_save(data) {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.step1_save,
|
||||
form: { ...form_data.submission.step1_save, ...data }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
|
||||
// Get submissionId from HTML
|
||||
const submissionUrl = jsonData.events[0].data;
|
||||
const parsedUrl = url.parse(submissionUrl, true);
|
||||
|
||||
this.submissionId = parsedUrl.query.submissionId;
|
||||
console.info("got submissionId:", this.submissionId);
|
||||
})
|
||||
.catch(err => console.error("Save step1 failed:", err));
|
||||
}
|
||||
|
||||
step2_getGenreId() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "GET",
|
||||
uri: endpoints.submission.step2.getGenreId,
|
||||
qs: {
|
||||
...form_data.submission.step2.getGenreId,
|
||||
submissionId: this.submissionId
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
// Get genreId from HTML
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const genreIdEl = $("option[label^='Текст статьи']").first();
|
||||
const genreId = genreIdEl.val();
|
||||
|
||||
return { genreId: genreId };
|
||||
})
|
||||
.catch(err =>
|
||||
console.error(
|
||||
"Fetching genreId (material pre-upload step) failed:",
|
||||
err
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
step2_upload(materialFilePath, genreId) {
|
||||
console.log("Uploading:", materialFilePath);
|
||||
|
||||
const fileName = path.basename(materialFilePath);
|
||||
const fileStream = fs.createReadStream(materialFilePath);
|
||||
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.uploadFile,
|
||||
headers: {
|
||||
browser_user_agent: this.client.apiDefaults.headers["User-Agent"]
|
||||
},
|
||||
qs: {
|
||||
...form_data.submission.step2.uploadQuery,
|
||||
submissionId: this.submissionId
|
||||
},
|
||||
formData: {
|
||||
genreId: genreId,
|
||||
name: fileName,
|
||||
uploadedFile: fileStream
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
console.info("Upload result:", jsonData);
|
||||
|
||||
// TODO Check JSON has certain info
|
||||
if (!jsonData || !jsonData.uploadedFile) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Material upload failed:", err));
|
||||
}
|
||||
|
||||
step2_save() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.step2.save,
|
||||
form: { submissionId: this.submissionId }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("Save step2 result:", jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Save step2 failed:", err));
|
||||
}
|
||||
|
||||
step3_metadata() {
|
||||
const info = {
|
||||
"title[ru_RU]": this.info.title_rus,
|
||||
"abstract[ru_RU]": this.info.abstract_rus,
|
||||
"keywords[ru_RU-keywords]": this.info.keywords
|
||||
};
|
||||
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.step3_metadata,
|
||||
form: {
|
||||
...form_data.submission.step3_metadata,
|
||||
...info,
|
||||
submissionId: this.submissionId
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("Step3 (metadata) result:", jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Step3 (metadata) failed:", err));
|
||||
}
|
||||
|
||||
step4_confirm() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.step4_confirm,
|
||||
form: { submissionId: this.submissionId }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("Step4 (confirmation) result:", jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Step4 (confirmation) failed:", err));
|
||||
}
|
||||
|
||||
createGalley() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.galley.create,
|
||||
qs: { submissionId: this.submissionId, representationId: "" },
|
||||
form: form_data.submission.galley.create
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("Create galley result:", jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
|
||||
const rowId = jsonData.events[0].data[0];
|
||||
console.log("Got rowId:", rowId);
|
||||
|
||||
return rowId;
|
||||
})
|
||||
.catch(err => console.error("Galley creation failed:", err));
|
||||
}
|
||||
|
||||
galley_getAssocTypeAssocId(rowId) {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "GET",
|
||||
uri: endpoints.submission.galley.getAssocTypeAssocId,
|
||||
qs: {
|
||||
rowId: rowId,
|
||||
submissionId: this.submissionId
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
// console.log('getAssocTypeAssocId data:', jsonData.content);
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
const assocTypeParam = jsonData.content.match(/assocType=\d+/);
|
||||
const assocType = assocTypeParam[0].split("=")[1];
|
||||
|
||||
const assocIdParam = jsonData.content.match(/assocId=\d+/);
|
||||
const assocId = assocIdParam[0].split("=")[1];
|
||||
|
||||
return { assocId: assocId, assocType: assocType };
|
||||
})
|
||||
.catch(err =>
|
||||
console.error(
|
||||
"Fetching assocType & assocId (material pre-upload step) failed:",
|
||||
err
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
galleyUpload(materialFilePath, genreId, assocType, assocId) {
|
||||
console.log("Uploading:", materialFilePath);
|
||||
|
||||
const fileName = path.basename(materialFilePath);
|
||||
const fileStream = fs.createReadStream(materialFilePath);
|
||||
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.uploadFile,
|
||||
headers: {
|
||||
browser_user_agent: this.client.apiDefaults.headers["User-Agent"]
|
||||
},
|
||||
qs: {
|
||||
...form_data.submission.galley.uploadQuery,
|
||||
submissionId: this.submissionId,
|
||||
assocType: assocType,
|
||||
assocId: assocId
|
||||
},
|
||||
formData: {
|
||||
genreId: genreId,
|
||||
name: fileName,
|
||||
uploadedFile: fileStream
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
console.info("Upload result:", jsonData);
|
||||
|
||||
// TODO Check JSON has certain info
|
||||
if (!jsonData || !jsonData.uploadedFile) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Galley material upload failed:", err));
|
||||
}
|
||||
|
||||
getAuthorsIds() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "GET",
|
||||
uri: endpoints.submission.getAuthors,
|
||||
qs: { submissionId: this.submissionId, stageId: 1 }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
// console.info('getAuthorsIds result:', jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
|
||||
var authorsIds = [];
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const $gridRows = $(".gridRow");
|
||||
$gridRows.each((i, r) => {
|
||||
const $r = $(r);
|
||||
const idAttr = $r.attr("id");
|
||||
const id = idAttr.split("-").slice(-1)[0];
|
||||
authorsIds.push(id);
|
||||
});
|
||||
|
||||
console.log("Got author ids:", authorsIds);
|
||||
|
||||
return authorsIds;
|
||||
})
|
||||
.catch(err => console.error("Authors fetching failed:", err));
|
||||
}
|
||||
|
||||
removeCreatorFromAuthorsList() {
|
||||
return this.getAuthorsIds()
|
||||
.then(authors => this.removeAuthor(authors[0]))
|
||||
.catch(err => console.error("removing submission creator failed:", err));
|
||||
}
|
||||
|
||||
removeAuthor(authorId) {
|
||||
console.log("Removing author with id:", authorId);
|
||||
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.removeAuthor,
|
||||
qs: { submissionId: this.submissionId, authorId: authorId }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("removeAuthor result:", jsonData);
|
||||
|
||||
if (!jsonData || !jsonData.events) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Author removal failed:", err));
|
||||
}
|
||||
|
||||
authorForm_getUserGroupId() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "GET",
|
||||
uri: endpoints.submission.authorForm,
|
||||
qs: { submissionId: this.submissionId }
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
|
||||
// Get genreId from HTML
|
||||
const $ = cheerio.load(jsonData.content);
|
||||
const userGroupEl = $("input[id^='userGroup']").first();
|
||||
const userGroupId = userGroupEl.val();
|
||||
|
||||
console.info("author form userGroupId:", userGroupId);
|
||||
|
||||
return userGroupId;
|
||||
})
|
||||
.catch(err => console.error("authorForm_getUserGroupId failed:", err));
|
||||
}
|
||||
|
||||
async addAuthor(userGroupId, info = {}) {
|
||||
return await this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.addAuthor,
|
||||
form: {
|
||||
...form_data.submission.addAuthor,
|
||||
...info,
|
||||
submissionId: this.submissionId,
|
||||
userGroupId: userGroupId
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("addAuthor result:", jsonData);
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Author adding failed:", err));
|
||||
}
|
||||
|
||||
async addAuthors(userGroupId) {
|
||||
console.info(`Start adding authors for submissionId ${this.submissionId}`);
|
||||
const totalAuthors = this.info.authors.length;
|
||||
|
||||
await helpers.asyncForEach(this.info.authors, async (authorInfo, i) => {
|
||||
console.info(`Adding author ${i + 1}/${totalAuthors}`);
|
||||
// console.info(authorInfo);
|
||||
await this.addAuthor(userGroupId, authorInfo);
|
||||
});
|
||||
}
|
||||
|
||||
attachIssue() {
|
||||
return this.client
|
||||
.sendJson({
|
||||
method: "POST",
|
||||
uri: endpoints.submission.save,
|
||||
form: {
|
||||
...form_data.submission.save,
|
||||
submissionId: this.submissionId,
|
||||
pages: this.info.pages,
|
||||
issueId: this.info.issueId
|
||||
}
|
||||
})
|
||||
.then(jsonData => {
|
||||
// TODO Check JSON has certain info
|
||||
console.info("attachIssue result:", jsonData);
|
||||
|
||||
if (!jsonData) Promise.reject();
|
||||
})
|
||||
.catch(err => console.error("Issue attaching failed:", err));
|
||||
}
|
||||
|
||||
async create(journalSlug, submissionInfo = {}) {
|
||||
this.client.setJournalUrl(journalSlug);
|
||||
this.info = submissionInfo;
|
||||
|
||||
return await this.prepare()
|
||||
.then(data => this.step1_save(data))
|
||||
.then(() => this.step2_getGenreId())
|
||||
.then(data => this.step2_upload(this.info.materialFilePath, data.genreId))
|
||||
.then(() => this.step2_save())
|
||||
.then(() => this.step3_metadata())
|
||||
.then(() => this.step4_confirm())
|
||||
|
||||
.then(() => this.createGalley())
|
||||
.then(rowId => {
|
||||
return Promise.all([
|
||||
this.galley_getAssocTypeAssocId(rowId),
|
||||
this.step2_getGenreId()
|
||||
]);
|
||||
})
|
||||
.then(data => {
|
||||
data = { ...data[0], ...data[1] };
|
||||
|
||||
console.log("Galley data:", data);
|
||||
this.galleyUpload(
|
||||
this.info.materialFilePath,
|
||||
data.genreId,
|
||||
data.assocType,
|
||||
data.assocId
|
||||
);
|
||||
})
|
||||
.then(() => this.removeCreatorFromAuthorsList())
|
||||
.then(() => this.authorForm_getUserGroupId())
|
||||
.then(async userGroupId => await this.addAuthors(userGroupId))
|
||||
.then(() => this.attachIssue())
|
||||
|
||||
.then(() => console.success("Submission created successfully"))
|
||||
.catch(err => console.error("Submission creation failed", err));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Submission;
|
||||
Loading…
Reference in New Issue
Block a user