mirror of
https://github.com/logos-co/open-law.git
synced 2025-02-13 07:16:25 +00:00
fork book without versions
This commit is contained in:
parent
de536841bd
commit
fd4af70587
110
app/controllers/fork.py
Normal file
110
app/controllers/fork.py
Normal file
@ -0,0 +1,110 @@
|
||||
from flask_login import current_user
|
||||
|
||||
from app import models as m
|
||||
from app.logger import log
|
||||
from app.controllers.create_access_groups import (
|
||||
create_editor_group,
|
||||
create_moderator_group,
|
||||
)
|
||||
|
||||
|
||||
def recursive_copy_collection(
|
||||
collection: m.Collection, parent_id: int, version_id: int
|
||||
):
|
||||
collection_copy = m.Collection(
|
||||
label=collection.label,
|
||||
about=collection.about,
|
||||
is_root=collection.is_root,
|
||||
is_leaf=collection.is_leaf,
|
||||
position=collection.position,
|
||||
parent_id=parent_id,
|
||||
version_id=version_id,
|
||||
)
|
||||
log(log.INFO, "Create copy of collection [%s]", collection)
|
||||
collection_copy.save()
|
||||
|
||||
if collection.active_sections:
|
||||
for section in collection.active_sections:
|
||||
section: m.Section
|
||||
section_copy = m.Section(
|
||||
label=section.label,
|
||||
collection_id=collection_copy.id,
|
||||
user_id=section.user_id,
|
||||
version_id=version_id,
|
||||
position=section.position,
|
||||
)
|
||||
log(log.INFO, "Create copy of section [%s]", section)
|
||||
section_copy.save()
|
||||
|
||||
interpretation: m.Interpretation = section.approved_interpretation
|
||||
if not interpretation:
|
||||
continue
|
||||
|
||||
interpretation_copy = m.Interpretation(
|
||||
text=interpretation.text,
|
||||
plain_text=interpretation.plain_text,
|
||||
approved=interpretation.approved,
|
||||
user_id=interpretation.user_id,
|
||||
section_id=section_copy.id,
|
||||
)
|
||||
log(log.INFO, "Create copy of interpretation [%s]", interpretation_copy)
|
||||
interpretation_copy.save()
|
||||
|
||||
comments: list[m.Comment] = section.approved_comments
|
||||
for comment in comments:
|
||||
comment_copy = m.Comment(
|
||||
text=comment.text,
|
||||
approved=comment.approved,
|
||||
edited=comment.edited,
|
||||
user_id=comment.user_id,
|
||||
interpretation_id=interpretation_copy.id,
|
||||
)
|
||||
log(log.INFO, "Create copy of comment [%s]", comment)
|
||||
comment_copy.save()
|
||||
|
||||
elif collection.active_children:
|
||||
for child in collection.active_children:
|
||||
recursive_copy_collection(child, collection_copy.id, version_id)
|
||||
|
||||
|
||||
def fork_book(book: m.Book, label: str, about: str):
|
||||
book_active_version: m.BookVersion = book.active_version
|
||||
book_root_collection: m.Collection = book_active_version.root_collection
|
||||
|
||||
book_copy: m.Book = m.Book(
|
||||
label=label, about=about, user_id=current_user.id, original_book_id=book.id
|
||||
)
|
||||
log(log.INFO, "Create fork of book [%s]", book)
|
||||
book_copy.save()
|
||||
|
||||
version = m.BookVersion(
|
||||
semver="Active", book_id=book_copy.id, is_active=True
|
||||
).save()
|
||||
log(log.INFO, "Create new version for book [%s]", book)
|
||||
version.save()
|
||||
|
||||
root_collection = m.Collection(
|
||||
label="Root Collection", version_id=version.id, is_root=True
|
||||
).save()
|
||||
|
||||
# access groups
|
||||
editor_access_group = create_editor_group(book_id=book.id)
|
||||
moderator_access_group = create_moderator_group(book_id=book.id)
|
||||
access_groups = [editor_access_group, moderator_access_group]
|
||||
|
||||
for access_group in access_groups:
|
||||
m.BookAccessGroups(book_id=book.id, access_group_id=access_group.id).save()
|
||||
m.CollectionAccessGroups(
|
||||
collection_id=root_collection.id, access_group_id=access_group.id
|
||||
).save()
|
||||
# -------------
|
||||
|
||||
# tags
|
||||
for tag in book.tags:
|
||||
m.BookTags(tag_id=tag.id, book_id=book_copy.id).save()
|
||||
# ----
|
||||
|
||||
for collection in book_root_collection.active_children:
|
||||
recursive_copy_collection(collection, root_collection.id, version.id)
|
||||
|
||||
return version
|
@ -19,3 +19,4 @@ from .vote import VoteForm
|
||||
from .comment import CreateCommentForm, DeleteCommentForm, EditCommentForm
|
||||
from .permission import EditPermissionForm
|
||||
from .version import EditVersionForm, DeleteVersionForm, CreateVersionForm
|
||||
from .fork import ForkBookForm
|
||||
|
8
app/forms/fork.py
Normal file
8
app/forms/fork.py
Normal file
@ -0,0 +1,8 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
class ForkBookForm(FlaskForm):
|
||||
label = StringField("Fork Label", [DataRequired()])
|
||||
about = StringField("Fork About")
|
@ -13,6 +13,7 @@ class Book(BaseModel):
|
||||
|
||||
# Foreign keys
|
||||
user_id = db.Column(db.ForeignKey("users.id"))
|
||||
original_book_id = db.Column(db.ForeignKey("books.id"))
|
||||
|
||||
# Relationships
|
||||
owner = db.relationship("User", viewonly=True)
|
||||
@ -31,6 +32,12 @@ class Book(BaseModel):
|
||||
secondary="book_tags",
|
||||
back_populates="books",
|
||||
)
|
||||
forks = db.relationship(
|
||||
"Book",
|
||||
backref=db.backref("original_book", remote_side="Book.id"),
|
||||
viewonly=True,
|
||||
order_by="asc(Book.id)",
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.id}: {self.label}>"
|
||||
|
@ -9,3 +9,4 @@ from . import section
|
||||
from . import interpretation
|
||||
from . import comment
|
||||
from . import version
|
||||
from . import fork
|
||||
|
30
app/views/book/fork.py
Normal file
30
app/views/book/fork.py
Normal file
@ -0,0 +1,30 @@
|
||||
from flask import flash, redirect, url_for
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from app import models as m, db, forms as f
|
||||
from app.controllers.fork import fork_book
|
||||
from app.logger import log
|
||||
from .bp import bp
|
||||
|
||||
|
||||
@bp.route("/<int:book_id>/fork", methods=["POST"])
|
||||
@login_required
|
||||
def fork(book_id):
|
||||
form: f.ForkBookForm = f.ForkBookForm()
|
||||
|
||||
book = db.session.get(m.Book, book_id)
|
||||
redirect_url = url_for("book.statistic_view", book_id=book.id, active_tab="forks")
|
||||
if form.validate_on_submit():
|
||||
if book.user_id == current_user.id:
|
||||
flash("You are owner of this book", "warning")
|
||||
return redirect(redirect_url)
|
||||
fork_book(book, form.label.data, form.about.data)
|
||||
flash("Success!", "success")
|
||||
return redirect(redirect_url)
|
||||
else:
|
||||
log(log.ERROR, "Fork book errors: [%s]", form.errors)
|
||||
for field, errors in form.errors.items():
|
||||
field_label = form._fields[field].label.text
|
||||
for error in errors:
|
||||
flash(error.replace("Field", field_label), "danger")
|
||||
return redirect(redirect_url)
|
38
tests/test_fork.py
Normal file
38
tests/test_fork.py
Normal file
@ -0,0 +1,38 @@
|
||||
from flask import current_app as Response
|
||||
from flask.testing import FlaskClient
|
||||
|
||||
from app import models as m
|
||||
from tests.utils import (
|
||||
login,
|
||||
logout,
|
||||
create_book,
|
||||
)
|
||||
|
||||
|
||||
def test_fork_book(client: FlaskClient):
|
||||
login(client)
|
||||
|
||||
book: m.Book = create_book(client)
|
||||
assert book
|
||||
assert len(book.forks) == 0
|
||||
|
||||
logout(client)
|
||||
_, user = login(client, "Test_U")
|
||||
|
||||
response: Response = client.post(
|
||||
f"/book/{book.id}/fork",
|
||||
data=dict(
|
||||
label="Label",
|
||||
about="About",
|
||||
),
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert b"Success" in response.data
|
||||
assert len(book.forks) == 1
|
||||
|
||||
assert user.books
|
||||
fork = user.books[0]
|
||||
assert fork.original_book_id == book.id
|
||||
assert fork.user_id != book.user_id
|
Loading…
x
Reference in New Issue
Block a user