Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature hooks #1492

Merged
merged 33 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d5691a2
Required or 1.3.8 plugins.
ajrbyers Feb 17, 2020
54354d5
Added migration.
ajrbyers Mar 9, 2020
2e61a68
Merged migrations
ajrbyers Mar 14, 2020
5f64f4e
Add support for args and kwargs on hooks
mauromsl Mar 18, 2020
c277869
Initial commit on hooks for plugins
ajrbyers Mar 30, 2020
20cb259
Updated the dashboard and editor block.
ajrbyers Apr 1, 2020
3f46e2f
More work towards 0.1.
ajrbyers Apr 2, 2020
1f93f31
Updates to complete some work in previous two commits.
ajrbyers Apr 2, 2020
a926990
Adds jump_url for plugin wf elements.
ajrbyers Apr 3, 2020
b32a45c
PEP8-ify copyedit.views.article_copyediting
ajrbyers Apr 6, 2020
0313bad
Merge branch 'feature-hooks' of github.com:BirkbeckCTP/janeway into f…
ajrbyers Apr 6, 2020
bb09f4c
Removed debug statement
ajrbyers Apr 6, 2020
8ba6d59
Reverts fix that is in another PR.
ajrbyers Apr 6, 2020
60cb5c6
Updated method name for clarity
ajrbyers Apr 7, 2020
428c935
Renamed current_stage_url to current_workflow_element_url for clairty…
ajrbyers Apr 7, 2020
4679b8d
Completes previous commit
ajrbyers Apr 7, 2020
9b4d553
Added reverse code to core.0034
ajrbyers Apr 7, 2020
9a87565
WorkflowElement.articles now uses self.journal instead of the global …
ajrbyers Apr 7, 2020
89ba531
Delete migrations and pushing wip!
ajrbyers Apr 8, 2020
1ce5e2d
Add stub for SomeClass
mauromsl Apr 8, 2020
127ad2e
Improves previous implementation
mauromsl Apr 8, 2020
78ec24f
Added a validation method to DynamicChoiceField
ajrbyers Apr 15, 2020
227b04c
Added better implementation of validate.
ajrbyers Apr 15, 2020
5733bd8
WorkflowElements that are plugins can expose some useful settings via…
ajrbyers Apr 15, 2020
16074a8
Changes DynamicChoiceFormField to be typed
mauromsl Apr 15, 2020
c23f4c9
Updated formfield to append dynamic_choices to choices. passed value …
ajrbyers Apr 15, 2020
aa6776a
Remove no longer needed formfield class
mauromsl Apr 15, 2020
6346595
Completed dashboard work for workflow plugins.
ajrbyers Apr 15, 2020
45cbb5d
Changed print errors to logger errors and removed pass.
ajrbyers Apr 16, 2020
2393d1c
use defaults to avoid duplicate plugins.
ajrbyers Apr 16, 2020
0e0d011
Added an implementation of DynamicChoiceField.validate that works.
ajrbyers Apr 17, 2020
3fecc25
UPdated error message
ajrbyers Apr 17, 2020
d5aa3df
core.workflow error loggers now work in production.
ajrbyers Apr 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,11 @@ def articles(self):
journal=self.journal,
)

@property
def settings(self):
from core import workflow
return workflow.workflow_plugin_settings(self)

def __str__(self):
return self.element_name

Expand Down
4 changes: 2 additions & 2 deletions src/core/plugin_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from django.db.utils import OperationalError, ProgrammingError

from core.workflow import ELEMENT_STAGES
from submission.models import STAGE_CHOICES
from submission.models import PLUGIN_WORKFLOW_STAGES
from utils import models
from utils.logic import get_janeway_version

Expand Down Expand Up @@ -49,7 +49,7 @@ def load(directory="plugins", prefix="plugins", permissive=False):
workflow_check = check_plugin_workflow(plugin_settings)
if workflow_check:
settings.WORKFLOW_PLUGINS[workflow_check] = module_name
STAGE_CHOICES.append(
PLUGIN_WORKFLOW_STAGES.append(
(plugin_settings.STAGE, plugin_settings.PLUGIN_NAME)
)
ELEMENT_STAGES[
Expand Down
34 changes: 34 additions & 0 deletions src/core/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ def articles_in_workflow_stages(request):
return workflow_list


def core_workflow_element_names():
return [element.get('name') for element in models.BASE_ELEMENTS]


def element_names(elements):
return [element.element_name for element in elements]

Expand Down Expand Up @@ -208,3 +212,33 @@ def remove_element(request, journal_workflow, element):
messages.SUCCESS,
'Element removed from workflow.'
)


def workflow_plugin_settings(element):
"""
Gets the plugin settings module for a plugin and returns useful settings
:param element: a WorkflowElement object
:return: dict of useful settings
"""
try:
settings_module = import_module(
settings.WORKFLOW_PLUGINS[element.element_name],
)

return {
'display_name': getattr(settings_module, 'DISPLAY_NAME', ''),
'description': getattr(settings_module, 'DESCRIPTION', ''),
'kanban_card': getattr(settings_module, 'KANBAN_CARD', ''),
'dashboard_template': getattr(
settings_module, 'DASHBOARD_TEMPLATE', ''
)
}

except (ImportError, KeyError) as e:
if settings.DEBUG:
print(e)
pass

return {}


6 changes: 6 additions & 0 deletions src/journal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ def article_keywords(self):
article__in=self.published_articles
).order_by('word')

@property
def workflow_plugin_elements(self):
return self.workflowelement_set.exclude(
element_name__in=workflow.core_workflow_element_names()
)


class PinnedArticle(models.Model):
journal = models.ForeignKey(Journal)
Expand Down
36 changes: 25 additions & 11 deletions src/submission/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from hvad.models import TranslatableModel, TranslatedFields
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.core.exceptions import ObjectDoesNotExist
from django.core import exceptions

from core.file_system import JanewayFileSystemStorage
from identifiers import logic as id_logic
Expand Down Expand Up @@ -243,6 +243,8 @@ def article_media_upload(instance, filename):
(STAGE_PREPRINT_PUBLISHED, 'Preprint Published')
]

PLUGIN_WORKFLOW_STAGES = []


class ArticleStageLog(models.Model):
article = models.ForeignKey('Article')
Expand Down Expand Up @@ -297,17 +299,28 @@ def get_queryset(self):
return super(PreprintManager, self).get_queryset().filter(is_preprint=True)


class SomeClass(ChoiceField):
def valid_value(self):
valid = super().valid_value()
if valid is False:
# check plugin stages


class DynamicChoiceField(models.CharField):
def __init__(self, dynamic_choices=(), *args, **kwargs):
super().__init__(*args, **kwargs)
self.dynamic_choices = dynamic_choices

def formfield(self, *args, **kwargs):
kwargs["choices_form_class"] = SomeClass
super().formfield(**kwargs)
form_element = super().formfield(**kwargs)
for choice in self.dynamic_choices:
form_element.choices.append(choice)
return form_element

def validate(self, value, model_instance):
"""
Validates value and throws ValidationError.
"""
try:
super().validate(value, model_instance)
except exceptions.ValidationError:
# Check if the value is in dynamic choices and remove the
# error message if it is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slightly inaccurate now

if 'invalid_choice' in self.error_messages and value in self.dynamic_choices:
self.error_messages.pop('invalid_choice')


class Article(models.Model):
Expand Down Expand Up @@ -385,6 +398,7 @@ class Article(models.Model):
null=False,
default=STAGE_UNSUBMITTED,
choices=STAGE_CHOICES,
dynamic_choices=PLUGIN_WORKFLOW_STAGES,
)

# Agreements
Expand Down Expand Up @@ -1077,7 +1091,7 @@ def close_core_workflow_objects(self):
def production_assignment_or_none(self):
try:
return self.productionassignment
except ObjectDoesNotExist:
except exceptions.ObjectDoesNotExist:
return None

@property
Expand Down
4 changes: 4 additions & 0 deletions src/templates/admin/core/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ <h2>Proofing Corrections</h2>
</div>
{% endif %}

{% for element in request.journal.workflow_plugin_elements %}
{% include element.settings.dashboard_template %}
{% endfor %}


{% user_has_role request 'section-editor' as sectioneditor %}
{% if sectioneditor %}
Expand Down