Coverage for portality/settings.py: 99%

237 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-11-09 16:22 +0000

1""" 

2~~AppSettings:Config~~ 

3""" 

4import os 

5from portality import constants 

6from portality.lib import paths 

7 

8########################################### 

9# Application Version information 

10# ~~->API:Feature~~ 

11 

12DOAJ_VERSION = "6.2.8" 

13API_VERSION = "3.0.1" 

14 

15###################################### 

16# Deployment configuration 

17 

18HOST = '0.0.0.0' 

19DEBUG = False 

20PORT = 5004 

21SSL = True 

22VALID_ENVIRONMENTS = ['dev', 'test', 'staging', 'production', 'harvester'] 

23CMS_BUILD_ASSETS_ON_STARTUP = False 

24# Cookies security 

25SESSION_COOKIE_SAMESITE='Strict' 

26SESSION_COOKIE_SECURE=True 

27REMEMBER_COOKIE_SECURE = True 

28 

29#################################### 

30# Debug Mode 

31 

32# PyCharm debug settings 

33DEBUG_PYCHARM = False # do not try to connect to the PyCharm debugger by default 

34DEBUG_PYCHARM_SERVER = 'localhost' 

35DEBUG_PYCHARM_PORT = 6000 

36 

37#~~->DebugToolbar:Framework~~ 

38DEBUG_TB_TEMPLATE_EDITOR_ENABLED = True 

39DEBUG_TB_INTERCEPT_REDIRECTS = False 

40 

41####################################### 

42# Elasticsearch configuration 

43#~~->Elasticsearch:Technology 

44 

45# elasticsearch settings # TODO: changing from single host / esprit to multi host on ES & correct the default 

46ELASTIC_SEARCH_HOST = os.getenv('ELASTIC_SEARCH_HOST', 'http://localhost:9200') # remember the http:// or https:// 

47ELASTICSEARCH_HOSTS = [{'host': 'localhost', 'port': 9200}, {'host': 'localhost', 'port': 9201}] 

48ELASTIC_SEARCH_VERIFY_CERTS = True # Verify the SSL certificate of the ES host. Set to False in dev.cfg to avoid having to configure your local certificates 

49 

50# 2 sets of elasticsearch DB settings - index-per-project and index-per-type. Keep both for now so we can migrate. 

51# e.g. host:port/index/type/id 

52ELASTIC_SEARCH_DB = "doaj" 

53ELASTIC_SEARCH_TEST_DB = "doajtest" 

54 

55# e.g. host:port/type/doc/id 

56ELASTIC_SEARCH_INDEX_PER_TYPE = True 

57INDEX_PER_TYPE_SUBSTITUTE = '_doc' # Migrated from esprit 

58ELASTIC_SEARCH_DB_PREFIX = "doaj-" # note: include the separator 

59ELASTIC_SEARCH_TEST_DB_PREFIX = "doajtest-" 

60 

61INITIALISE_INDEX = True # whether or not to try creating the index and required index types on startup 

62ELASTIC_SEARCH_VERSION = "1.7.5" 

63ELASTIC_SEARCH_SNAPSHOT_REPOSITORY = None 

64ELASTIC_SEARCH_SNAPSHOT_TTL = 366 

65 

66ES_TERMS_LIMIT = 1024 

67 

68##################################################### 

69# Elastic APM config (MUST be configured in env file) 

70# ~~->APM:Feature~~ 

71 

72ENABLE_APM = False 

73 

74ELASTIC_APM = { 

75 # Set required service name. Allowed characters: 

76 # a-z, A-Z, 0-9, -, _, and space 

77 'SERVICE_NAME': '', 

78 

79 # Use if APM Server requires a token 

80 'SECRET_TOKEN': '', 

81 

82 # Set custom APM Server URL (default: http://localhost:8200) 

83 'SERVER_URL': '', 

84} 

85 

86########################################### 

87# Event handler 

88 

89# use this to queue events asynchronously through kafka 

90EVENT_SEND_FUNCTION = "portality.events.kafka_producer.send_event" 

91# use this one to bypass kafka and process events immediately/synchronously 

92# EVENT_SEND_FUNCTION = "portality.events.shortcircuit.send_event" 

93 

94KAFKA_BROKER = "kafka://localhost:9092" 

95KAFKA_EVENTS_TOPIC = "events" 

96KAFKA_BOOTSTRAP_SERVER = "localhost:9092" 

97 

98########################################### 

99# Read Only Mode 

100# 

101# Use these options to place the application into READ ONLY mode 

102 

103# This puts the UI into READ_ONLY mode 

104# ~~->ReadOnlyMode:Feature~~ 

105READ_ONLY_MODE = False 

106 

107# This puts the cron jobs into READ_ONLY mode 

108SCRIPTS_READ_ONLY_MODE = False 

109 

110 

111########################################### 

112# Feature Toggles 

113 

114# ~~->OfflineMode:Feature~~ 

115OFFLINE_MODE = False 

116 

117# List the features we want to be active (API v1 and v2 remain with redirects to v3) 

118# ~~->API:Feature~~ 

119FEATURES = ['api1', 'api2', 'api3'] 

120VALID_FEATURES = ['api1', 'api2', 'api3'] 

121 

122######################################## 

123# File Path and URL Path settings 

124 

125# root of the git repo 

126ROOT_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..") 

127 

128# base path, to the directory where this settings file lives 

129BASE_FILE_PATH = os.path.dirname(os.path.realpath(__file__)) 

130 

131BASE_URL = "https://doaj.org" 

132if BASE_URL.startswith('https://'): 

133 BASE_DOMAIN = BASE_URL[8:] 

134elif BASE_URL.startswith('http://'): 

135 BASE_DOMAIN = BASE_URL[7:] 

136else: 

137 BASE_DOMAIN = BASE_URL 

138 

139# ~~->API:Feature~~ 

140BASE_API_URL = "https://doaj.org/api/" 

141API_CURRENT_BLUEPRINT_NAME = "api_v3" # change if upgrading API to new version and creating new view 

142 

143# URL used for the journal ToC URL in the journal CSV export 

144# NOTE: must be the correct route as configured in view/doaj.py 

145# ~~->ToC:WebRoute~~ 

146JOURNAL_TOC_URL_FRAG = BASE_URL + '/toc/' 

147 

148# Used when generating external links, e.g. in the API docs 

149PREFERRED_URL_SCHEME = 'https' 

150 

151# Whether the app is running behind a proxy, for generating URLs based on X-Forwarded-Proto 

152# ~~->ProxyFix:Framework~~ 

153PROXIED = False 

154 

155# directory to upload files to. MUST be full absolute path 

156# The default takes the directory above this, and then down in to "upload" 

157UPLOAD_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "upload") 

158FAILED_ARTICLE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "failed_articles") 

159 

160# directory where reports are output 

161REPORTS_BASE_DIR = "/home/cloo/reports/" 

162 

163################################## 

164# File store 

165# ~~->FileStore:Feature~~ 

166 

167# put this in your production.cfg, to store on S3: 

168# STORE_IMPL = "portality.store.StoreS3" 

169 

170STORE_IMPL = "portality.store.StoreLocal" 

171STORE_TMP_IMPL = "portality.store.TempStore" 

172 

173STORE_LOCAL_DIR = paths.rel2abs(__file__, "..", "local_store", "main") 

174STORE_TMP_DIR = paths.rel2abs(__file__, "..", "local_store", "tmp") 

175STORE_LOCAL_EXPOSE = False # if you want to allow files in the local store to be exposed under /store/<path> urls. For dev only. 

176STORE_LOCAL_WRITE_BUFFER_SIZE = 16777216 

177STORE_TMP_WRITE_BUFFER_SIZE = 16777216 

178 

179# containers (buckets in AWS) where various content will be stored 

180# These values are placeholders, and must be overridden in live deployment 

181# this prevents test environments from accidentally writing to the production buckets 

182STORE_ANON_DATA_CONTAINER = "doaj-anon-data-placeholder" 

183STORE_CACHE_CONTAINER = "doaj-data-cache-placeholder" 

184STORE_PUBLIC_DATA_DUMP_CONTAINER = "doaj-data-dump-placeholder" 

185STORE_HARVESTER_CONTAINER = "doaj-harvester" 

186 

187# S3 credentials for relevant scopes 

188# ~~->S3:Technology~~ 

189STORE_S3_SCOPES = { 

190 "anon_data" : { 

191 "aws_access_key_id" : "put this in your dev/test/production.cfg", 

192 "aws_secret_access_key" : "put this in your dev/test/production.cfg" 

193 }, 

194 "cache" : { 

195 "aws_access_key_id" : "put this in your dev/test/production.cfg", 

196 "aws_secret_access_key" : "put this in your dev/test/production.cfg" 

197 }, 

198 # Used by the api_export script to dump data from the api 

199 "public_data_dump" : { 

200 "aws_access_key_id" : "put this in your dev/test/production.cfg", 

201 "aws_secret_access_key" : "put this in your dev/test/production.cfg" 

202 }, 

203 # Used to store harvester run logs to S3 

204 "harvester" : { 

205 "aws_access_key_id" : "put this in your dev/test/production.cfg", 

206 "aws_secret_access_key" : "put this in your dev/test/production.cfg" 

207 } 

208} 

209 

210STORE_S3_MULTIPART_THRESHOLD = 5 * 1024**3 # 5GB 

211 

212#################################### 

213# CMS configuration 

214 

215# paths where static content should be served from. 

216# * in the order you want them searched 

217# * relative to the portality directory 

218# ~~->CMS:DataStore~~ 

219STATIC_PATHS = [ 

220 "static", 

221 "../cms/assets" 

222] 

223 

224# GitHub base url where static content can be edited by the DOAJ team (you can leave out the trailing slash) 

225#~~->GitHub:ExternalService~~ 

226CMS_EDIT_BASE_URL = "https://github.com/DOAJ/doaj/edit/static_pages/cms" 

227 

228# Where static files are served from - in case we need to serve a file 

229# from there ourselves using Flask instead of nginx (e.g. to support a 

230# legacy route to that file) 

231# Changing this will not change the actual folder that Flask serves 

232# static files from. 

233# http://flask.pocoo.org/snippets/102/ 

234STATIC_DIR = os.path.join(ROOT_DIR, "portality", "static") 

235 

236###################################### 

237# Service Descriptive Text 

238 

239SERVICE_NAME = "Directory of Open Access Journals" 

240SERVICE_TAGLINE = "DOAJ is an online directory that indexes and provides access to quality open access, peer-reviewed journals." 

241 

242################################### 

243# Cookie settings 

244 

245# make this something secret in your overriding app.cfg 

246# ~~->Cookies:Feature~~ 

247SECRET_KEY = "default-key" 

248 

249 

250# Consent Cookie and other Top-Level dismissable notes 

251# ~~->ConsentCookie:Feature~~ 

252CONSENT_COOKIE_KEY = "doaj-cookie-consent" 

253 

254# site notes, which can be configured to run any time with any content 

255# ~~-> SiteNote:Feature~~ 

256SITE_NOTE_ACTIVE = False 

257SITE_NOTE_KEY = "doaj-site-note" 

258SITE_NOTE_SLEEP = 259200 # every 3 days 

259SITE_NOTE_COOKIE_VALUE = "You have seen our most recent site wide announcement" 

260SITE_NOTE_TEMPLATE = "doaj/site_note.html" 

261 

262#################################### 

263# Authorisation settings 

264# ~~->AuthNZ:Feature~~ 

265 

266# Can people register publicly? If false, only the superuser can create new accounts 

267PUBLIC_REGISTER = True 

268 

269SUPER_USER_ROLE = "admin" 

270 

271LOGIN_VIA_ACCOUNT_ID = True 

272 

273# amount of time a reset token is valid for (86400 is 24 hours) 

274PASSWORD_RESET_TIMEOUT = 86400 

275# amount of time a reset token for a new account is valid for 

276PASSWORD_CREATE_TIMEOUT = PASSWORD_RESET_TIMEOUT * 14 

277 

278#"api" top-level role is added to all acounts on creation; it can be revoked per account by removal of the role. 

279TOP_LEVEL_ROLES = ["admin", "publisher", "editor", "associate_editor", "api", "ultra_bulk_delete", "preservation"] 

280 

281ROLE_MAP = { 

282 "editor": [ 

283 "associate_editor", # note, these don't cascade, so we still need to list all the low-level roles 

284 "edit_journal", 

285 "edit_suggestion", 

286 "edit_application", # todo: switchover from suggestion to application 

287 "editor_area", 

288 "assign_to_associate", 

289 "list_group_journals", 

290 "list_group_suggestions", 

291 ], 

292 "associate_editor": [ 

293 "edit_journal", 

294 "edit_suggestion", 

295 "editor_area", 

296 ] 

297} 

298 

299# If you change the reserved usernames, your data will likely need a migration to remove their 

300# existing use in the system. 

301SYSTEM_USERNAME = "system" 

302RESERVED_USERNAMES = [SYSTEM_USERNAME] # do not allow the creation of user accounts with this id 

303 

304# Role map to destination route on login (when no other destination page is present) 

305# checked in order, if the user has the role in the first tuple position, they will 

306# be redirected to the endpoint in the second tuple position 

307ROLE_LOGIN_DESTINATIONS = [ 

308 ("admin", "dashboard.top_todo"), 

309 ("editor", "editor.index"), 

310 ("associate_editor", "editor.index"), 

311 ("publisher", "publisher.index") 

312] 

313 

314# if the user doesn't have one of the above roles, where should they be sent after login 

315DEFAULT_LOGIN_DESTINATION = "doaj.home" 

316 

317#################################### 

318# Email Settings 

319# ~~->Email:ExternalService 

320 

321# Settings for Flask-Mail. Set in app.cfg 

322MAIL_SERVER = None # default localhost 

323MAIL_PORT = 25 # default 25 

324#MAIL_USE_TLS # default False 

325#MAIL_USE_SSL # default False 

326#MAIL_DEBUG # default app.debug 

327#MAIL_USERNAME # default None 

328#MAIL_PASSWORD # default None 

329#MAIL_DEFAULT_SENDER # default None 

330#MAIL_MAX_EMAILS # default None 

331#MAIL_SUPPRESS_SEND # default app.testing 

332 

333ENABLE_EMAIL = True 

334ENABLE_PUBLISHER_EMAIL = True 

335 

336ADMIN_NAME = "DOAJ" 

337ADMIN_EMAIL = "sysadmin@cottagelabs.com" 

338ADMINS = ["steve@cottagelabs.com", "mark@cottagelabs.com"] 

339 

340MANAGING_EDITOR_EMAIL = "managing-editors@doaj.org" 

341CONTACT_FORM_ADDRESS = "feedback+contactform@doaj.org" 

342SCRIPT_TAG_DETECTED_EMAIL_RECIPIENTS = ["helpdesk@doaj.org"] 

343 

344SYSTEM_EMAIL_FROM = 'helpdesk@doaj.org' 

345CC_ALL_EMAILS_TO = SYSTEM_EMAIL_FROM # DOAJ may get a dedicated inbox in the future 

346 

347# Error logging via email 

348SUPPRESS_ERROR_EMAILS = False 

349ERROR_LOGGING_EMAIL = 'doaj.internal@gmail.com' 

350ERROR_MAIL_HOSTNAME = 'smtp.mailgun.org' 

351ERROR_MAIL_USERNAME = None 

352ERROR_MAIL_PASSWORD = None 

353 

354# Reports email recipient 

355REPORTS_EMAIL_TO = ["helpdesk@doaj.org"] 

356 

357######################################## 

358# workflow email notification settings 

359# ~~->WorkflowNotifications:Feature~~ 

360 

361MAN_ED_IDLE_WEEKS = 4 # weeks before an application is considered reminder-worthy 

362ED_IDLE_WEEKS = 3 # weeks before the editor is warned about idle applications in their group 

363ASSOC_ED_IDLE_DAYS = 10 

364ASSOC_ED_IDLE_WEEKS = 3 

365 

366# Which statuses the notification queries should be filtered to show 

367MAN_ED_NOTIFICATION_STATUSES = [ 

368 constants.APPLICATION_STATUS_PENDING, 

369 constants.APPLICATION_STATUS_IN_PROGRESS, constants.APPLICATION_STATUS_COMPLETED, 

370 constants.APPLICATION_STATUS_ON_HOLD 

371] 

372ED_NOTIFICATION_STATUSES = [ 

373 constants.APPLICATION_STATUS_PENDING, 

374 constants.APPLICATION_STATUS_IN_PROGRESS, 

375 constants.APPLICATION_STATUS_COMPLETED 

376] 

377ASSOC_ED_NOTIFICATION_STATUSES = [ 

378 constants.APPLICATION_STATUS_PENDING, 

379 constants.APPLICATION_STATUS_IN_PROGRESS 

380] 

381 

382################################### 

383# status endpoint configuration 

384# ~~->StatusEndpoint:Feature~~ 

385 

386# /status endpoint connection to all app machines 

387APP_MACHINES_INTERNAL_IPS = [HOST + ':' + str(PORT)] # This should be set in production.cfg (or dev.cfg etc) 

388 

389########################################### 

390# Background Jobs settings 

391# ~~->Huey:Technology~~ 

392# ~~->Redis:Technology~~ 

393# ~~->BackgroundTasks:Feature~~ 

394 

395# huey/redis settings 

396HUEY_REDIS_HOST = os.getenv('HUEY_REDIS_HOST', '127.0.0.1') 

397HUEY_REDIS_PORT = os.getenv('HUEY_REDIS_PORT', 6379) 

398HUEY_EAGER = False 

399 

400# Crontab for never running a job - February 31st (use to disable tasks) 

401CRON_NEVER = {"month": "2", "day": "31", "day_of_week": "*", "hour": "*", "minute": "*"} 

402 

403# Crontab schedules must be for unique times to avoid delays due to perceived race conditions 

404HUEY_SCHEDULE = { 

405 "sitemap": {"month": "*", "day": "*", "day_of_week": "*", "hour": "8", "minute": "0"}, 

406 "reporting": {"month": "*", "day": "1", "day_of_week": "*", "hour": "0", "minute": "0"}, 

407 "journal_csv": {"month": "*", "day": "*", "day_of_week": "*", "hour": "*", "minute": "35"}, 

408 "read_news": {"month": "*", "day": "*", "day_of_week": "*", "hour": "*", "minute": "30"}, 

409 "article_cleanup_sync": {"month": "*", "day": "2", "day_of_week": "*", "hour": "0", "minute": "0"}, 

410 "async_workflow_notifications": {"month": "*", "day": "*", "day_of_week": "1", "hour": "5", "minute": "0"}, 

411 "request_es_backup": {"month": "*", "day": "*", "day_of_week": "*", "hour": "6", "minute": "0"}, 

412 "check_latest_es_backup": {"month": "*", "day": "*", "day_of_week": "*", "hour": "9", "minute": "0"}, 

413 "prune_es_backups": {"month": "*", "day": "*", "day_of_week": "*", "hour": "9", "minute": "15"}, 

414 "public_data_dump": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"}, 

415 "harvest": {"month": "*", "day": "*", "day_of_week": "*", "hour": "5", "minute": "30"}, 

416 "anon_export": {"month": "*", "day": "10", "day_of_week": "*", "hour": "6", "minute": "30"}, 

417} 

418 

419HUEY_TASKS = { 

420 "ingest_articles": {"retries": 10, "retry_delay": 15}, 

421 "preserve": {"retries": 0, "retry_delay": 15} 

422} 

423 

424#################################### 

425# publisher area settings 

426 

427# the earliest date accepted on the publisher's 'enter article metadata' form. 

428# code will default to 15 years before current year if commented out. 

429# ~~->ArticleMetadata:Page~~ 

430METADATA_START_YEAR = 1960 

431 

432# tick (on toc) and doaj seal settings 

433# ~~->Tick:Feature~~ 

434TICK_THRESHOLD = '2014-03-19T00:00:00Z' 

435 

436# ~~->UpdateRequests:Feature~~ 

437UPDATE_REQUESTS_SHOW_OLDEST = "2018-01-01T00:00:00Z" 

438 

439############################################## 

440# Elasticsearch Mappings 

441# ~~->Elasticsearch:Technology~~ 

442 

443FACET_FIELD = ".exact" 

444 

445# an array of DAO classes from which to retrieve the type-specific ES mappings 

446# to be loaded into the index during initialisation. 

447ELASTIC_SEARCH_MAPPINGS = [ 

448 "portality.models.Journal", # ~~->Journal:Model~~ 

449 "portality.models.Application", # ~~->Application:Model~~ 

450 "portality.models.DraftApplication", # ~~-> DraftApplication:Model~~ 

451 "portality.models.harvester.HarvestState", # ~~->HarvestState:Model~~ 

452 "portality.models.background.BackgroundJob" # ~~-> BackgroundJob:Model~~ 

453] 

454 

455# Map from dataobj coercion declarations to ES mappings 

456# ~~->DataObj:Library~~ 

457# ~~->Seamless:Library~~ 

458DATAOBJ_TO_MAPPING_DEFAULTS = { 

459 "unicode": { 

460 "type": "text", 

461 "fields": { 

462 "exact": { 

463 "type": "keyword", 

464# "index": False, 

465 "store": True 

466 } 

467 } 

468 }, 

469 "str": { 

470 "type": "text", 

471 "fields": { 

472 "exact": { 

473 "type": "keyword", 

474# "index": False, 

475 "store": True 

476 } 

477 } 

478 }, 

479 "unicode_upper": { 

480 "type": "text", 

481 "fields": { 

482 "exact": { 

483 "type": "keyword", 

484# "index": False, 

485 "store": True 

486 } 

487 } 

488 }, 

489 "unicode_lower": { 

490 "type": "text", 

491 "fields": { 

492 "exact": { 

493 "type": "keyword", 

494# "index": False, 

495 "store": True 

496 } 

497 } 

498 }, 

499 "isolang": { 

500 "type": "text", 

501 "fields": { 

502 "exact": { 

503 "type": "keyword", 

504# "index": False, 

505 "store": True 

506 } 

507 } 

508 }, 

509 "isolang_2letter": { 

510 "type": "text", 

511 "fields": { 

512 "exact": { 

513 "type": "keyword", 

514# "index": False, 

515 "store": True 

516 } 

517 } 

518 }, 

519 "country_code": { 

520 "type": "text", 

521 "fields": { 

522 "exact": { 

523 "type": "keyword", 

524# "index": False, 

525 "store": True 

526 } 

527 } 

528 }, 

529 "currency_code": { 

530 "type": "text", 

531 "fields": { 

532 "exact": { 

533 "type": "keyword", 

534# "index": False, 

535 "store": True 

536 } 

537 } 

538 }, 

539 "issn": { 

540 "type": "text", 

541 "fields": { 

542 "exact": { 

543 "type": "keyword", 

544# "index": False, 

545 "store": True 

546 } 

547 } 

548 }, 

549 "url": { 

550 "type": "text", 

551 "fields": { 

552 "exact": { 

553 "type": "keyword", 

554# "index": False, 

555 "store": True 

556 } 

557 } 

558 }, 

559 "utcdatetimemicros": { 

560 "type": "date", 

561 "format": "date_optional_time" 

562 }, 

563 "utcdatetime": { 

564 "type": "date", 

565 "format": "date_optional_time" 

566 }, 

567 "bool": { 

568 "type": "boolean" 

569 }, 

570 "integer": { 

571 "type": "long" 

572 }, 

573 "bigenddate": { 

574 "type": "date", 

575 "format": "date_optional_time" 

576 }, 

577 "year": { 

578 "type": "date", 

579 "format": "year" 

580 } 

581} 

582 

583# TODO: we may want a big-type and little-type setting 

584DEFAULT_INDEX_SETTINGS = \ 

585 { 

586 'number_of_shards': 4, 

587 'number_of_replicas': 1 

588 } 

589 

590 

591DEFAULT_DYNAMIC_MAPPING = { 

592 'dynamic_templates': [ 

593 { 

594 "strings": { 

595 "match_mapping_type": "string", 

596 "mapping": { 

597 "type": "text", 

598 "fields": { 

599 "exact": { 

600 "type": "keyword", 

601 #"normalizer": "lowercase" 

602 } 

603 } 

604 } 

605 } 

606 } 

607 ] 

608} 

609 

610# LEGACY MAPPINGS 

611# a dict of the ES mappings. identify by name, and include name as first object name 

612# and identifier for how non-analyzed fields for faceting are differentiated in the mappings 

613MAPPINGS = { 

614 'account': { #~~->Account:Model~~ 

615 # 'aliases': { 

616 # 'account': {} 

617 # }, 

618 'mappings': DEFAULT_DYNAMIC_MAPPING, 

619 'settings': DEFAULT_INDEX_SETTINGS 

620 } 

621} 

622# MAPPINGS['article'] = {'article': DEFAULT_DYNAMIC_MAPPING} #~~->Article:Model~~ 

623# MAPPINGS['upload'] = {'upload': DEFAULT_DYNAMIC_MAPPING} #~~->Upload:Model~~ 

624# MAPPINGS['cache'] = {'cache': DEFAULT_DYNAMIC_MAPPING} #~~->Cache:Model~~ 

625# MAPPINGS['lcc'] = {'lcc': DEFAULT_DYNAMIC_MAPPING} #~~->LCC:Model~~ 

626# MAPPINGS['editor_group'] = {'editor_group': DEFAULT_DYNAMIC_MAPPING} #~~->EditorGroup:Model~~ 

627# MAPPINGS['news'] = {'news': DEFAULT_DYNAMIC_MAPPING} #~~->News:Model~~ 

628# MAPPINGS['lock'] = {'lock': DEFAULT_DYNAMIC_MAPPING} #~~->Lock:Model~~ 

629# MAPPINGS['provenance'] = {'provenance': DEFAULT_DYNAMIC_MAPPING} #~~->Provenance:Model~~ 

630# MAPPINGS['preserve'] = {'preserve': DEFAULT_DYNAMIC_MAPPING} #~~->Preservation:Model~~ 

631 

632MAPPINGS['article'] = MAPPINGS["account"] #~~->Article:Model~~ 

633MAPPINGS['upload'] = MAPPINGS["account"] #~~->Upload:Model~~ 

634MAPPINGS['cache'] = MAPPINGS["account"] #~~->Cache:Model~~ 

635MAPPINGS['lcc'] = MAPPINGS["account"] #~~->LCC:Model~~ 

636MAPPINGS['editor_group'] = MAPPINGS["account"] #~~->EditorGroup:Model~~ 

637MAPPINGS['news'] = MAPPINGS["account"] #~~->News:Model~~ 

638MAPPINGS['lock'] = MAPPINGS["account"] #~~->Lock:Model~~ 

639MAPPINGS['provenance'] = MAPPINGS["account"] #~~->Provenance:Model~~ 

640MAPPINGS['preserve'] = MAPPINGS["account"] #~~->Preservation:Model~~ 

641MAPPINGS['notification'] = MAPPINGS["account"] #~~->Notification:Model~~ 

642 

643######################################### 

644# Query Routes 

645# ~~->Query:WebRoute~~ 

646 

647QUERY_ROUTE = { 

648 "query" : { 

649 # ~~->PublicJournalQuery:Endpoint~~ 

650 "journal" : { 

651 "auth" : False, 

652 "role" : None, 

653 "query_validator" : "public_query_validator", 

654 "query_filters" : ["only_in_doaj", "last_update_fallback"], 

655 "result_filters" : ["public_result_filter"], 

656 "dao" : "portality.models.Journal", # ~~->Journal:Model~~ 

657 "required_parameters" : {"ref" : ["ssw", "public_journal", "subject_page"]} 

658 }, 

659 # ~~->PublicArticleQuery:Endpoint~~ 

660 "article" : { 

661 "auth" : False, 

662 "role" : None, 

663 "query_validator" : "public_query_validator", 

664 "query_filters" : ["only_in_doaj"], 

665 "result_filters" : ["public_result_filter"], 

666 "dao" : "portality.models.Article", # ~~->Article:Model~~ 

667 "required_parameters" : {"ref" : ["public_article", "toc", "subject_page"]} 

668 }, 

669 # back-compat for fixed query widget 

670 # ~~->PublicJournalArticleQuery:Endpoint~~ 

671 "journal,article" : { 

672 "auth" : False, 

673 "role" : None, 

674 "query_validator" : "public_query_validator", 

675 "query_filters" : ["only_in_doaj", "strip_facets", "es_type_fix"], 

676 "result_filters" : ["public_result_filter", "add_fqw_facets", "fqw_back_compat"], 

677 "dao" : "portality.models.JournalArticle", # ~~->JournalArticle:Model~~ 

678 "required_parameters" : {"ref" : ["fqw"]} 

679 } 

680 }, 

681 "publisher_query" : { 

682 # ~~->PublisherJournalQuery:Endpoint~~ 

683 "journal" : { 

684 "auth" : True, 

685 "role" : "publisher", 

686 "query_filters" : ["owner", "only_in_doaj"], 

687 "result_filters" : ["publisher_result_filter"], 

688 "dao" : "portality.models.Journal" # ~~->Journal:Model~~ 

689 }, 

690 # ~~->PublisherApplicationQuery:Endpoint~~ 

691 "applications" : { 

692 "auth" : True, 

693 "role" : "publisher", 

694 "query_filters" : ["owner", "not_update_request"], 

695 "result_filters" : ["publisher_result_filter"], 

696 "dao" : "portality.models.AllPublisherApplications" # ~~->AllPublisherApplications:Model~~ 

697 }, 

698 # ~~->PublisherUpdateRequestsQuery:Endpoint~~ 

699 "update_requests" : { 

700 "auth" : True, 

701 "role" : "publisher", 

702 "query_filters" : ["owner", "update_request"], 

703 "result_filters" : ["publisher_result_filter"], 

704 "dao" : "portality.models.Application" # ~~->Application:Model~~ 

705 } 

706 }, 

707 "admin_query" : { 

708 # ~~->AdminJournalQuery:Endpoint~~ 

709 "journal" : { 

710 "auth" : True, 

711 "role" : "admin", 

712 "dao" : "portality.models.Journal" # ~~->Journal:Model~~ 

713 }, 

714 # ~~->AdminApplicationQuery:Endpoint~~ 

715 "suggestion" : { 

716 "auth" : True, 

717 "role" : "admin", 

718 "query_filters" : ["not_update_request"], 

719 "dao" : "portality.models.Application" # ~~->Application:Model~~ 

720 }, 

721 # ~~->AdminUpdateRequestQuery:Endpoint~~ 

722 "update_requests": { 

723 "auth": True, 

724 "role": "admin", 

725 "query_filters" : ["update_request"], 

726 "dao": "portality.models.Application" # ~~->Application:Model~~ 

727 }, 

728 # ~~->AdminEditorGroupQuery:Endpoint~~ 

729 "editor,group" : { 

730 "auth" : True, 

731 "role" : "admin", 

732 "dao" : "portality.models.EditorGroup" # ~~->EditorGroup:Model~~ 

733 }, 

734 # ~~->AdminAccountQuery:Endpoint~~ 

735 "account" : { 

736 "auth" : True, 

737 "role" : "admin", 

738 "dao" : "portality.models.Account" # ~~->Account:Model~~ 

739 }, 

740 # ~~->AdminJournalArticleQuery:Endpoint~~ 

741 "journal,article" : { 

742 "auth" : True, 

743 "role" : "admin", 

744 "dao" : "portality.models.search.JournalArticle" # ~~->JournalArticle:Model~~ 

745 }, 

746 # ~~->AdminBackgroundJobQuery:Endpoint~~ 

747 "background,job" : { 

748 "auth" : True, 

749 "role" : "admin", 

750 "dao" : "portality.models.BackgroundJob" # ~~->BackgroundJob:Model~~ 

751 } 

752 }, 

753 "associate_query" : { 

754 # ~~->AssEdJournalQuery:Endpoint~~ 

755 "journal" : { 

756 "auth" : True, 

757 "role" : "associate_editor", 

758 "query_filters" : ["associate"], 

759 "dao" : "portality.models.Journal" # ~~->Journal:Model~~ 

760 }, 

761 # ~~->AssEdApplicationQuery:Endpoint~~ 

762 "suggestion" : { 

763 "auth" : True, 

764 "role" : "associate_editor", 

765 "query_filters" : ["associate"], 

766 "dao" : "portality.models.Application" # ~~->Application:Model~~ 

767 } 

768 }, 

769 "editor_query" : { 

770 # ~~->EditorJournalQuery:Endpoint~~ 

771 "journal" : { 

772 "auth" : True, 

773 "role" : "editor", 

774 "query_filters" : ["editor"], 

775 "dao" : "portality.models.Journal" # ~~->Journal:Model~~ 

776 }, 

777 # ~~->EditorApplicationQuery:Endpoint~~ 

778 "suggestion" : { 

779 "auth" : True, 

780 "role" : "editor", 

781 "query_filters" : ["editor"], 

782 "dao" : "portality.models.Application" # ~~->Application:Model~~ 

783 } 

784 }, 

785 "api_query" : { 

786 # ~~->APIArticleQuery:Endpoint~~ 

787 "article" : { 

788 "auth" : False, 

789 "role" : None, 

790 "query_filters" : ["only_in_doaj", "public_source"], 

791 "dao" : "portality.models.Article", # ~~->Article:Model~~ 

792 "required_parameters" : None, 

793 "keepalive" : "10m" 

794 }, 

795 # ~~->APIJournalQuery:Endpoint~~ 

796 "journal" : { 

797 "auth" : False, 

798 "role" : None, 

799 "query_filters" : ["only_in_doaj", "public_source"], 

800 "dao" : "portality.models.Journal", # ~~->Journal:Model~~ 

801 "required_parameters" : None 

802 }, 

803 # ~~->APIApplicationQuery:Endpoint~~ 

804 "application" : { 

805 "auth" : True, 

806 "role" : None, 

807 "query_filters" : ["owner", "private_source"], 

808 "dao" : "portality.models.Suggestion", # ~~->Application:Model~~ 

809 "required_parameters" : None 

810 } 

811 } 

812} 

813 

814QUERY_FILTERS = { 

815 # sanitisers 

816 "public_query_validator" : "portality.lib.query_filters.public_query_validator", 

817 

818 # query filters 

819 "only_in_doaj" : "portality.lib.query_filters.only_in_doaj", 

820 "owner" : "portality.lib.query_filters.owner", 

821 "update_request" : "portality.lib.query_filters.update_request", 

822 "associate" : "portality.lib.query_filters.associate", 

823 "editor" : "portality.lib.query_filters.editor", 

824 "strip_facets" : "portality.lib.query_filters.strip_facets", 

825 "es_type_fix" : "portality.lib.query_filters.es_type_fix", 

826 "last_update_fallback" : "portality.lib.query_filters.last_update_fallback", 

827 "not_update_request" : "portality.lib.query_filters.not_update_request", 

828 

829 # result filters 

830 "public_result_filter": "portality.lib.query_filters.public_result_filter", 

831 "publisher_result_filter": "portality.lib.query_filters.publisher_result_filter", 

832 "add_fqw_facets" : "portality.lib.query_filters.add_fqw_facets", 

833 "fqw_back_compat" : "portality.lib.query_filters.fqw_back_compat", 

834 

835 # source filters 

836 "private_source": "portality.lib.query_filters.private_source", 

837 "public_source": "portality.lib.query_filters.public_source", 

838} 

839 

840#################################################### 

841# Autocomplete 

842 

843# ~~->BibJSON:Model~~ 

844AUTOCOMPLETE_ADVANCED_FIELD_MAPS = { 

845 "bibjson.publisher.name" : "index.publisher_ac", 

846 "bibjson.institution.name" : "index.institution_ac" 

847} 

848 

849#################################################### 

850# Application Form 

851# ~~->ApplicationForm:Feature~~ 

852 

853# save the public application form as a draft every 60 seconds 

854PUBLIC_FORM_AUTOSAVE = 60000 

855 

856 

857############################################ 

858# Atom Feed 

859# ~~->AtomFeed:Feature~~ 

860 

861FEED_TITLE = "DOAJ Recent Journals Added" 

862 

863# Maximum number of feed entries to be given in a single response. If this is omitted, it will 

864# default to 20 

865MAX_FEED_ENTRIES = 100 

866 

867# Maximum age of feed entries (in seconds) (default value here is 30 days). 

868MAX_FEED_ENTRY_AGE = 2592000 

869 

870# Licensing terms for feed content 

871# ~~->SiteLicence:Content~~ 

872FEED_LICENCE = "(c) DOAJ 2013. CC BY-SA." 

873 

874# name of the feed generator (goes in the atom:generator element) 

875FEED_GENERATOR = "CottageLabs feed generator" 

876 

877# Larger image to use as the logo for all of the feeds 

878# ~~->Favicon:Content~~ 

879FEED_LOGO = "https://doaj.org/static/doaj/images/favicon.ico" 

880 

881 

882########################################### 

883# OAI-PMH SETTINGS 

884# ~~->OAIPMH:Feature~~ 

885 

886# ~~->OAIAriticleXML:Crosswalk~~ 

887# ~~->OAIJournalXML:Crosswalk~~ 

888OAI_DC_METADATA_FORMAT = { 

889 "metadataPrefix": "oai_dc", 

890 "schema": "http://www.openarchives.org/OAI/2.0/oai_dc.xsd", 

891 "metadataNamespace": "http://www.openarchives.org/OAI/2.0/oai_dc/" 

892} 

893 

894OAI_DOAJ_METADATA_FORMAT = { 

895 "metadataPrefix": "oai_doaj", 

896 "schema": "https://doaj.org/static/doaj/doajArticles.xsd", 

897 "metadataNamespace": "https://doaj.org/features/oai_doaj/1.0/" 

898} 

899 

900OAIPMH_METADATA_FORMATS = { 

901 # "specific endpoint": [list, of, formats, supported] 

902 

903 None: [OAI_DC_METADATA_FORMAT], # no specific endpoint, the request is to the root /oai path 

904 "article": [OAI_DC_METADATA_FORMAT, OAI_DOAJ_METADATA_FORMAT] 

905} 

906 

907OAIPMH_IDENTIFIER_NAMESPACE = "doaj.org" 

908 

909OAIPMH_LIST_RECORDS_PAGE_SIZE = 100 

910 

911OAIPMH_LIST_IDENTIFIERS_PAGE_SIZE = 300 

912 

913OAIPMH_RESUMPTION_TOKEN_EXPIRY = 86400 

914 

915 

916########################################## 

917# Article XML configuration 

918 

919# paths to schema files to validate incoming documents against for the various 

920# crosswalks available 

921# ~~->CrossrefXML:Schema~~ 

922# ~~->DOAJArticleXML:Schema~~ 

923SCHEMAS = { 

924 "doaj": os.path.join(BASE_FILE_PATH, "static", "doaj", "doajArticles.xsd"), 

925 "crossref442": os.path.join(BASE_FILE_PATH, "static", "crossref", "crossref4.4.2.xsd"), 

926 "crossref531": os.path.join(BASE_FILE_PATH, "static", "crossref", "crossref5.3.1.xsd") 

927} 

928 

929# placeholders for the loaded schemas 

930DOAJ_SCHEMA = None 

931CROSSREF442_SCHEMA = None 

932CROSSREF531_SCHEMA = None 

933LOAD_CROSSREF_THREAD = None 

934 

935# mapping of format names to modules which implement the crosswalks 

936# ~~->DOAJArticleXML:Crosswalk~~ 

937# ~~->CrossrefXML:Crosswalk~~ 

938ARTICLE_CROSSWALKS = { 

939 "doaj": "portality.crosswalks.article_doaj_xml.DOAJXWalk", 

940 "crossref442": "portality.crosswalks.article_crossref_xml.CrossrefXWalk442", 

941 "crossref531": "portality.crosswalks.article_crossref_xml.CrossrefXWalk531" 

942} 

943 

944# maximum size of files that can be provided by-reference (the default value is 250Mb) 

945MAX_REMOTE_SIZE = 262144000 

946 

947################################################# 

948# Cache settings 

949# ~~->Cache:Feature~~ 

950 

951# number of seconds site statistics should be considered fresh 

952# 1800s = 30mins 

953SITE_STATISTICS_TIMEOUT = 1800 

954 

955# directory into which to put files which are cached (e.g. the csv) 

956CACHE_DIR = os.path.join(ROOT_DIR, "cache") 

957 

958# Article and Journal History directories - they should be different 

959# ~~->ArticleHistory:Feature~~ 

960# ~~->JournalHistory:Feature~~ 

961ARTICLE_HISTORY_DIR = os.path.join(ROOT_DIR, "history", "article") 

962JOURNAL_HISTORY_DIR = os.path.join(ROOT_DIR, "history", "journal") 

963 

964 

965################################################# 

966# Sitemap settings 

967# ~~->Sitemap:Feature~~ 

968 

969# approximate rate of change of the Table of Contents for journals 

970TOC_CHANGEFREQ = "monthly" 

971 

972 

973 

974################################################## 

975# News feed settings 

976# ~~->News:Feature~~ 

977 

978BLOG_URL = "http://doajournals.wordpress.com/" 

979 

980BLOG_FEED_URL = "http://doajournals.wordpress.com/feed/atom/" 

981 

982FRONT_PAGE_NEWS_ITEMS = 6 

983 

984NEWS_PAGE_NEWS_ITEMS = 20 

985 

986 

987################################################## 

988# Edit Lock settings 

989# ~~->Lock:Feature~~ 

990 

991# amount of time loading an editable page locks it for, in seconds. 

992EDIT_LOCK_TIMEOUT = 1200 

993 

994# amount of time a background task can lock a resource for, in seconds 

995BACKGROUND_TASK_LOCK_TIMEOUT = 3600 

996 

997 

998############################################### 

999# Bit.ly configuration 

1000# ~~->Bitly:ExternalService~~ 

1001 

1002# bit,ly api shortening service 

1003BITLY_SHORTENING_API_URL = "https://api-ssl.bitly.com/v4/shorten" 

1004 

1005# bitly oauth token 

1006# ENTER YOUR OWN TOKEN IN APPROPRIATE .cfg FILE 

1007BITLY_OAUTH_TOKEN = "" 

1008 

1009############################################### 

1010# Date handling 

1011# 

1012# when dates.format is called without a format argument, what format to use? 

1013# FIXME: this is actually wrong - should really use the timezone correctly 

1014DEFAULT_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" 

1015 

1016# date formats that we know about, and should try, in order, when parsing 

1017DATE_FORMATS = [ 

1018 "%Y-%m-%dT%H:%M:%S.%fZ", # e.g. 2010-01-01T00:00:00.000Z 

1019 "%Y-%m-%dT%H:%M:%SZ", # e.g. 2014-09-23T11:30:45Z 

1020 "%Y-%m-%d", # e.g. 2014-09-23 

1021 "%d/%m/%y", # e.g. 29/02/80 

1022 "%d/%m/%Y", # e.g. 29/02/1980 

1023 "%d-%m-%Y", # e.g. 01-01-2015 

1024 "%Y.%m.%d", # e.g. 2014.09.12 

1025 "%d.%m.%Y", # e.g. 12.9.2014 

1026 "%d.%m.%y", # e.g. 12.9.14 

1027 "%d %B %Y", # e.g. 21 June 2014 

1028 "%d-%b-%Y", # e.g. 31-Jul-13 

1029 "%d-%b-%y", # e.g. 31-Jul-2013 

1030 "%b-%y", # e.g. Aug-13 

1031 "%B %Y", # e.g. February 2014 

1032 "%Y" # e.g. 1978 

1033] 

1034 

1035# The last_manual_update field was initialised to this value. Used to label as 'never'. 

1036DEFAULT_TIMESTAMP = "1970-01-01T00:00:00Z" 

1037 

1038################################################# 

1039# API configuration 

1040# ~~->API:Feature~~ 

1041# ~~->APISearch:Feature~~ 

1042 

1043# maximum number of records to return per page 

1044DISCOVERY_MAX_PAGE_SIZE = 100 

1045 

1046# maximum number of records to return in total (a request for a page starting beyond this number will fail) 

1047DISCOVERY_MAX_RECORDS_SIZE = 1000 

1048 

1049# ~~->ArticleBibJSON:Model~~ 

1050DISCOVERY_ARTICLE_SEARCH_SUBS = { 

1051 "title" : "bibjson.title", 

1052 "doi" : "bibjson.identifier.id.exact", 

1053 "issn" : "index.issn.exact", 

1054 "publisher" : "bibjson.journal.publisher", 

1055 "journal" : "bibjson.journal.title", 

1056 "abstract" : "bibjson.abstract" 

1057} 

1058 

1059DISCOVERY_ARTICLE_SORT_SUBS = { 

1060 "title" : "index.unpunctitle.exact" 

1061} 

1062 

1063# ~~->JournalBibJSON:Model~~ 

1064DISCOVERY_JOURNAL_SEARCH_SUBS = { 

1065 "title" : "index.title", 

1066 "issn" : "index.issn.exact", 

1067 "publisher" : "bibjson.publisher", 

1068 "license" : "index.license.exact", 

1069 "username" : "admin.owner.exact" 

1070} 

1071 

1072DISCOVERY_JOURNAL_SORT_SUBS = { 

1073 "title" : "index.unpunctitle.exact", 

1074 "issn" : "index.issn.exact" 

1075} 

1076 

1077DISCOVERY_APPLICATION_SEARCH_SUBS = { 

1078 "title" : "index.title", 

1079 "issn" : "index.issn.exact", 

1080 "publisher" : "bibjson.publisher", 

1081 "license" : "index.license.exact" 

1082} 

1083 

1084DISCOVERY_APPLICATION_SORT_SUBS = { 

1085 "title" : "index.unpunctitle.exact", 

1086 "issn" : "index.issn.exact" 

1087} 

1088 

1089# API data dump settings 

1090DISCOVERY_BULK_PAGE_SIZE = 1000 

1091DISCOVERY_RECORDS_PER_FILE = 100000 

1092 

1093 

1094###################################################### 

1095# Hotjar configuration 

1096# ~~->Hotjar:ExternalService~~ 

1097 

1098# hotjar id - only activate this in production 

1099HOTJAR_ID = "" 

1100 

1101 

1102###################################################### 

1103# Google Analytics configuration 

1104# specify in environment .cfg file - avoids sending live analytics 

1105# events from test and dev environments 

1106# ~~->GoogleAnalytics:ExternalService~~ 

1107 

1108GOOGLE_ANALYTICS_ID = '' 

1109 

1110# Where to put the google analytics logs 

1111GOOGLE_ANALTYICS_LOG_DIR = None 

1112 

1113# Google Analytics custom dimensions. These are configured in the GA interface. 

1114GA_DIMENSIONS = { 

1115 'oai_res_id': 'dimension1', # In GA as OAI:Record 

1116} 

1117 

1118# GA for OAI-PMH 

1119# ~~-> OAIPMH:Feature~~ 

1120GA_CATEGORY_OAI = 'OAI-PMH' 

1121 

1122# GA for Atom 

1123# ~~-> Atom:Feature~~ 

1124GA_CATEGORY_ATOM = 'Atom' 

1125GA_ACTION_ACTION = 'Feed request' 

1126 

1127# GA for JournalCSV 

1128# ~~-> JournalCSV:Feature~~ 

1129GA_CATEGORY_JOURNALCSV = 'JournalCSV' 

1130GA_ACTION_JOURNALCSV = 'Download' 

1131 

1132# GA for OpenURL 

1133# ~~->OpenURL:Feature~~ 

1134GA_CATEGORY_OPENURL = 'OpenURL' 

1135 

1136# GA for API 

1137# ~~-> API:Feature~~ 

1138GA_CATEGORY_API = 'API Hit' 

1139GA_ACTIONS_API = { 

1140 'search_applications': 'Search applications', 

1141 'search_journals': 'Search journals', 

1142 'search_articles': 'Search articles', 

1143 'create_application': 'Create application', 

1144 'retrieve_application': 'Retrieve application', 

1145 'update_application': 'Update application', 

1146 'delete_application': 'Delete application', 

1147 'create_article': 'Create article', 

1148 'retrieve_article': 'Retrieve article', 

1149 'update_article': 'Update article', 

1150 'delete_article': 'Delete article', 

1151 'retrieve_journal': 'Retrieve journal', 

1152 'bulk_application_create': 'Bulk application create', 

1153 'bulk_application_delete': 'Bulk application delete', 

1154 'bulk_article_create': 'Bulk article create', 

1155 'bulk_article_delete': 'Bulk article delete' 

1156} 

1157 

1158 

1159# GA for fixed query widget 

1160# ~~->FixedQueryWidget:Feature~~ 

1161GA_CATEGORY_FQW = 'FQW' 

1162GA_ACTION_FQW = 'Hit' 

1163 

1164##################################################### 

1165# Anonymised data export (for dev) configuration 

1166# ~~->AnonExport:Feature~~ 

1167 

1168ANON_SALT = 'changeme' 

1169 

1170# ======================================== 

1171# Quick Reject Feature Config 

1172# ~~->QuickReject:Feature~~ 

1173 

1174QUICK_REJECT_REASONS = [ 

1175 "The journal has not published enough research content to qualify for DOAJ inclusion.", 

1176 "The ISSN is incorrect, provisional or not registered with issn.org.", 

1177 "The URL(s) provided in the application do not work.", 

1178 "The journal is already in DOAJ.", 

1179 "The journal is not Open Access.", 

1180 "The journal title in the application and/or website does not match the title at issn.org.", 

1181 "The application has incorrect answers or the URLs given do not provide the required information.", 

1182 "This application is a duplicate.", 

1183 "The full-text articles are not available article by article with individual links.", 

1184 "The information in the journal implies that it does not employ a fair & robust peer review process.", 

1185 "The journal or publisher has been previously rejected or removed from DOAJ.", 

1186 "The journal's copyright policy is not available or unclear.", 

1187 "The journal's licensing policy is not available or unclear.", 

1188 "The information about the journal is in different languages.", 

1189 "The information about the journal is not the same in all languages.", 

1190 "The journal makes a false claim to be indexed in DOAJ or other databases or displays non-standard Impact Factors.", 

1191 "The journal does not employ good publishing practices." 

1192] 

1193 

1194MINIMAL_OA_START_DATE = 1900 

1195 

1196 

1197############################################# 

1198## Harvester Configuration 

1199# ~~->Harvester:Feature~~ 

1200 

1201## Configuration options for the DOAJ API Client 

1202 

1203## EPMC Client configuration 

1204# ~~-> EPMC:ExternalService~~ 

1205EPMC_REST_API = "https://www.ebi.ac.uk/europepmc/webservices/rest/" 

1206EPMC_TARGET_VERSION = "6.6" # doc here: https://europepmc.org/docs/Europe_PMC_RESTful_Release_Notes.pdf 

1207EPMC_HARVESTER_THROTTLE = 0.2 

1208 

1209# General harvester configuration 

1210HARVESTERS = [ 

1211 "portality.tasks.harvester_helpers.epmc.epmc_harvester.EPMCHarvester" 

1212] 

1213 

1214INITIAL_HARVEST_DATE = "2015-12-01T00:00:00Z" 

1215 

1216# List of account ids to harvest from. MUST NOT be checked into the repo, put these 

1217# in the local.cfg instead 

1218HARVEST_ACCOUNTS = [] 

1219 

1220# Amount of time a harvester record is allowed to be in "queued" or "processing" state before we 

1221# assume it's a zombie, and ignore it 

1222HARVESTER_ZOMBIE_AGE = 604800 

1223 

1224####################################################### 

1225# ReCAPTCHA configuration 

1226# ~~->ReCAPTCHA:ExternalService 

1227 

1228#Recaptcha test keys, should be overridden in dev.cfg by the keys obtained from Google ReCaptcha v2 

1229RECAPTCHA_ENABLE = True 

1230RECAPTCHA_SITE_KEY = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' 

1231RECAPTCHA_SECRET_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" 

1232 

1233####################################################### 

1234# Preservation configuration 

1235# ~~->Preservation:Feature 

1236PRESERVATION_URL = "http://PresevatinURL" 

1237PRESERVATION_USERNAME = "user_name" 

1238PRESERVATION_PASSWD = "password" 

1239PRESERVATION_COLLECTION = {} 

1240 

1241 

1242######################################################### 

1243# Background tasks --- anon export 

1244TASKS_ANON_EXPORT_CLEAN = False 

1245TASKS_ANON_EXPORT_LIMIT = None 

1246TASKS_ANON_EXPORT_BATCH_SIZE = 100000 

1247 

1248######################################## 

1249# Editorial Dashboard - set to-do list size 

1250TODO_LIST_SIZE = 48 

1251 

1252####################################################### 

1253# Plausible analytics 

1254# root url of plausible 

1255PLAUSIBLE_URL = "https://plausible.io" 

1256PLAUSIBLE_JS_URL = PLAUSIBLE_URL + "/js/plausible.js" 

1257PLAUSIBLE_API_URL = PLAUSIBLE_URL + "/api/event/" 

1258# site name / domain name that used to register in plausible 

1259PLAUSIBLE_SITE_NAME = BASE_DOMAIN 

1260PLAUSIBLE_LOG_DIR = None