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