mirror of https://github.com/logos-co/open-law.git
Merge pull request #28 from Simple2B/kostia/feature/interpretations
work
This commit is contained in:
commit
2d20671eaf
|
@ -1,10 +1,7 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, SubmitField, ValidationError
|
from wtforms import StringField, SubmitField
|
||||||
from wtforms.validators import DataRequired, Length
|
from wtforms.validators import DataRequired, Length
|
||||||
|
|
||||||
from app import models as m, db
|
|
||||||
from app.logger import log
|
|
||||||
|
|
||||||
|
|
||||||
class BaseInterpretationForm(FlaskForm):
|
class BaseInterpretationForm(FlaskForm):
|
||||||
label = StringField("Label", [DataRequired(), Length(3, 256)])
|
label = StringField("Label", [DataRequired(), Length(3, 256)])
|
||||||
|
@ -16,47 +13,8 @@ class CreateInterpretationForm(BaseInterpretationForm):
|
||||||
text = StringField("Text")
|
text = StringField("Text")
|
||||||
submit = SubmitField("Create")
|
submit = SubmitField("Create")
|
||||||
|
|
||||||
def validate_label(self, field):
|
|
||||||
label = field.data
|
|
||||||
section_id = self.section_id.data
|
|
||||||
|
|
||||||
interpretation: m.Interpretation = m.Interpretation.query.filter_by(
|
|
||||||
is_deleted=False, label=label, section_id=section_id
|
|
||||||
).first()
|
|
||||||
if interpretation:
|
|
||||||
log(
|
|
||||||
log.WARNING,
|
|
||||||
"Interpretation with label [%s] already exists: [%s]",
|
|
||||||
label,
|
|
||||||
interpretation,
|
|
||||||
)
|
|
||||||
raise ValidationError("Interpretation label must be unique!")
|
|
||||||
|
|
||||||
|
|
||||||
class EditInterpretationForm(BaseInterpretationForm):
|
class EditInterpretationForm(BaseInterpretationForm):
|
||||||
interpretation_id = StringField("Interpretation ID", [DataRequired()])
|
interpretation_id = StringField("Interpretation ID", [DataRequired()])
|
||||||
text = StringField("Text")
|
text = StringField("Text")
|
||||||
submit = SubmitField("Edit")
|
submit = SubmitField("Edit")
|
||||||
|
|
||||||
def validate_label(self, field):
|
|
||||||
label = field.data
|
|
||||||
interpretation_id = self.interpretation_id.data
|
|
||||||
|
|
||||||
section_id = db.session.get(m.Interpretation, interpretation_id).section_id
|
|
||||||
|
|
||||||
interpretation: m.Interpretation = (
|
|
||||||
m.Interpretation.query.filter_by(
|
|
||||||
is_deleted=False, label=label, section_id=section_id
|
|
||||||
)
|
|
||||||
.filter(m.Interpretation.id != interpretation_id)
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
if interpretation:
|
|
||||||
log(
|
|
||||||
log.WARNING,
|
|
||||||
"Interpretation with label [%s] already exists: [%s]",
|
|
||||||
label,
|
|
||||||
interpretation,
|
|
||||||
)
|
|
||||||
raise ValidationError("Interpretation label must be unique!")
|
|
||||||
|
|
|
@ -47,5 +47,13 @@ class Section(BaseModel):
|
||||||
_sub_collection_id = grand_parent.id
|
_sub_collection_id = grand_parent.id
|
||||||
return _sub_collection_id
|
return _sub_collection_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_interpretations(self):
|
||||||
|
return [
|
||||||
|
interpretation
|
||||||
|
for interpretation in self.interpretations
|
||||||
|
if not interpretation.is_deleted
|
||||||
|
]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.id}: {self.label}>"
|
return f"<{self.id}: {self.label}>"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -66,7 +66,7 @@
|
||||||
<input type="hidden" name="section_id" id="section_id" value="{{section.id}}" />
|
<input type="hidden" name="section_id" id="section_id" value="{{section.id}}" />
|
||||||
<input type="hidden" name="label" id="label" value="{{section.label}}" />
|
<input type="hidden" name="label" id="label" value="{{section.label}}" />
|
||||||
|
|
||||||
<input type="hidden" name="interpretation-text" id="interpretation-text" />
|
<input type="hidden" name="text" id="interpretation-text" />
|
||||||
<!-- Form body -->
|
<!-- Form body -->
|
||||||
<div class="p-6 space-y-6">
|
<div class="p-6 space-y-6">
|
||||||
<div class="grid gap-6">
|
<div class="grid gap-6">
|
||||||
|
@ -89,20 +89,21 @@
|
||||||
</form>
|
</form>
|
||||||
<dl class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700">
|
<dl class="w-md md:w-full text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700">
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
{% for interpretation in section.interpretations %}
|
{% for interpretation in section.active_interpretations %}
|
||||||
{% if sub_collection %}
|
{% if sub_collection %}
|
||||||
<a href="{{url_for('book.interpretation_view', book_id=book.id, collection_id=collection.id, sub_collection_id=sub_collection.id, section_id=section.id)}}" >
|
<a href="{{url_for('book.interpretation_view', book_id=book.id, collection_id=collection.id, sub_collection_id=sub_collection.id, section_id=section.id)}}" >
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{url_for('book.interpretation_view', book_id=book.id, collection_id=collection.id, section_id=section.id)}}" >
|
<a href="{{url_for('book.interpretation_view', book_id=book.id, collection_id=collection.id, section_id=section.id)}}" >
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h1>Other</h1>
|
|
||||||
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
|
<dl class="bg-white dark:bg-gray-900 max-w-full p-3 text-gray-900 divide-y divide-gray-200 dark:text-white dark:divide-gray-700 m-3 border-2 border-gray-200 border-solid rounded-lg dark:border-gray-700">
|
||||||
<div class="flex flex-col pb-3 p-3 w-full">
|
<div class="flex flex-col pb-3 p-3 w-full">
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
|
<dt class="flex w-full mb-1 text-gray-500 md:text-lg dark:text-gray-400 flex-col">
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ section.label }}</h1>
|
<h1>{{ section.label }}</h1>
|
||||||
<p>{{ interpretation.text }}</p>
|
<div id="editor" class="dark:text-white h-80">
|
||||||
|
<p>{{ interpretation.text|safe }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex ml-auto align-center justify-center space-x-3">
|
<div class="flex ml-auto align-center justify-center space-x-3">
|
||||||
<span class="space-x-0.5 flex items-center">
|
<span class="space-x-0.5 flex items-center">
|
||||||
|
|
|
@ -912,17 +912,25 @@ def interpretation_create(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
redirect_url = url_for(
|
|
||||||
"book.section_view",
|
|
||||||
book_id=book_id,
|
|
||||||
collection_id=collection_id,
|
|
||||||
sub_collection_id=sub_collection_id,
|
|
||||||
)
|
|
||||||
section: m.Section = db.session.get(m.Section, section_id)
|
section: m.Section = db.session.get(m.Section, section_id)
|
||||||
if not section or collection.is_deleted:
|
if not section or collection.is_deleted:
|
||||||
log(log.WARNING, "Section with id [%s] not found", section)
|
log(log.WARNING, "Section with id [%s] not found", section)
|
||||||
flash("Section not found", "danger")
|
flash("Section not found", "danger")
|
||||||
return redirect(redirect_url)
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"book.section_view",
|
||||||
|
book_id=book_id,
|
||||||
|
collection_id=collection_id,
|
||||||
|
sub_collection_id=sub_collection_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
redirect_url = url_for(
|
||||||
|
"book.interpretation_view",
|
||||||
|
book_id=book_id,
|
||||||
|
collection_id=collection_id,
|
||||||
|
sub_collection_id=sub_collection_id,
|
||||||
|
section_id=section.id,
|
||||||
|
)
|
||||||
|
|
||||||
form = f.CreateInterpretationForm()
|
form = f.CreateInterpretationForm()
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,39 @@
|
||||||
const quill_value_to_textarea = (): undefined => {
|
const quill_value_to_textarea = (): undefined => {
|
||||||
const aboutInput: HTMLButtonElement = document.querySelector('#about');
|
const aboutInput: HTMLInputElement = document.querySelector('#about');
|
||||||
const qlEditor: HTMLButtonElement = document.querySelector('.ql-editor');
|
const qlEditor: HTMLElement = document.querySelector('.ql-editor');
|
||||||
const editorContent = qlEditor.innerHTML;
|
const editorContent = qlEditor.innerHTML;
|
||||||
aboutInput.value = editorContent;
|
aboutInput.value = editorContent;
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
const quill_interpretation_to_textarea = (): undefined => {
|
const quill_interpretation_to_textarea = (): undefined => {
|
||||||
const interpretationTextInput: HTMLButtonElement = document.querySelector(
|
const interpretationTextInput: HTMLInputElement = document.querySelector(
|
||||||
'#interpretation-text',
|
'#interpretation-text',
|
||||||
);
|
);
|
||||||
const qlInterpretationEditor: HTMLButtonElement = document.querySelector(
|
const qlInterpretationEditor: HTMLElement = document.querySelector(
|
||||||
'.ql-interpretation-editor',
|
'#interpretation-editor',
|
||||||
);
|
);
|
||||||
const editorContent = qlInterpretationEditor.innerHTML;
|
const editorContent = qlInterpretationEditor.innerHTML;
|
||||||
|
console.log('editorContent', editorContent);
|
||||||
interpretationTextInput.value = editorContent;
|
interpretationTextInput.value = editorContent;
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function initQuillValueToTextArea() {
|
export function initQuillValueToTextArea() {
|
||||||
const qlEditor: HTMLButtonElement = document.querySelector('.ql-editor');
|
const qlEditor: HTMLElement = document.querySelector('.ql-editor');
|
||||||
|
|
||||||
if (qlEditor) {
|
if (qlEditor) {
|
||||||
qlEditor.addEventListener('DOMSubtreeModified', async e => {
|
qlEditor.addEventListener('DOMSubtreeModified', () => {
|
||||||
quill_value_to_textarea();
|
quill_value_to_textarea();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
const qlInterpretationEditor: HTMLButtonElement = document.querySelector(
|
const qlInterpretationEditor: HTMLElement = document.querySelector(
|
||||||
'.ql-interpretation-editor',
|
'#interpretation-editor',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!qlInterpretationEditor) {
|
if (qlInterpretationEditor) {
|
||||||
qlInterpretationEditor.addEventListener('DOMSubtreeModified', async e => {
|
qlInterpretationEditor.addEventListener('DOMSubtreeModified', () => {
|
||||||
quill_interpretation_to_textarea();
|
quill_interpretation_to_textarea();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -757,14 +757,6 @@ def test_crud_interpretation(client: FlaskClient, runner: FlaskCliRunner):
|
||||||
assert interpretation.section_id == section_in_subcollection.id
|
assert interpretation.section_id == section_in_subcollection.id
|
||||||
assert not interpretation.comments
|
assert not interpretation.comments
|
||||||
|
|
||||||
response: Response = client.post(
|
|
||||||
f"/book/{book.id}/{collection.id}/{sub_collection.id}/{section_in_subcollection.id}/create_interpretation",
|
|
||||||
data=dict(section_id=section_in_subcollection.id, label=label_1, text=text_1),
|
|
||||||
follow_redirects=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert b"Interpretation label must be unique!" in response.data
|
|
||||||
|
|
||||||
response: Response = client.post(
|
response: Response = client.post(
|
||||||
f"/book/{book.id}/{leaf_collection.id}/{section_in_collection.id}/create_interpretation",
|
f"/book/{book.id}/{leaf_collection.id}/{section_in_collection.id}/create_interpretation",
|
||||||
data=dict(section_id=section_in_collection.id, label=label_1, text=text_1),
|
data=dict(section_id=section_in_collection.id, label=label_1, text=text_1),
|
||||||
|
@ -779,14 +771,6 @@ def test_crud_interpretation(client: FlaskClient, runner: FlaskCliRunner):
|
||||||
assert interpretation.section_id == section_in_collection.id
|
assert interpretation.section_id == section_in_collection.id
|
||||||
assert not interpretation.comments
|
assert not interpretation.comments
|
||||||
|
|
||||||
response: Response = client.post(
|
|
||||||
f"/book/{book.id}/{leaf_collection.id}/{section_in_collection.id}/create_interpretation",
|
|
||||||
data=dict(section_id=section_in_collection.id, label=label_1, text=text_1),
|
|
||||||
follow_redirects=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert b"Interpretation label must be unique!" in response.data
|
|
||||||
|
|
||||||
response: Response = client.post(
|
response: Response = client.post(
|
||||||
f"/book/{book.id}/{collection.id}/999/create_section",
|
f"/book/{book.id}/{collection.id}/999/create_section",
|
||||||
data=dict(collection_id=999, label=label_1, text=text_1),
|
data=dict(collection_id=999, label=label_1, text=text_1),
|
||||||
|
@ -832,19 +816,6 @@ def test_crud_interpretation(client: FlaskClient, runner: FlaskCliRunner):
|
||||||
label=label_1, section_id=section_in_collection.id
|
label=label_1, section_id=section_in_collection.id
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
response: Response = client.post(
|
|
||||||
f"/book/{book.id}/{leaf_collection.id}/{section_in_collection.id}/{interpretation.id}/edit_interpretation",
|
|
||||||
data=dict(
|
|
||||||
interpretation_id=interpretation.id,
|
|
||||||
label="Test",
|
|
||||||
text="Test",
|
|
||||||
),
|
|
||||||
follow_redirects=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert b"Interpretation label must be unique!" in response.data
|
|
||||||
|
|
||||||
new_label = "Test Interpretation #1 Label(edited)"
|
new_label = "Test Interpretation #1 Label(edited)"
|
||||||
new_text = "Test Interpretation #1 Text(edited)"
|
new_text = "Test Interpretation #1 Text(edited)"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue