mirror of
https://git.cmoser.eu/tinytools/django-tinywiki.git
synced 2026-02-04 06:06:33 +01:00
371 lines
14 KiB
Python
371 lines
14 KiB
Python
from pathlib import Path
|
|
import json
|
|
import zipfile
|
|
import os
|
|
import sys
|
|
|
|
from .models import Image, Page, BuiltinImages, BuiltinPages, get_tinywiki_default_user
|
|
from .enums import WikiContentType, WikiPageStatus
|
|
from django.core.files.images import ImageFile
|
|
from django.conf import settings as django_settings
|
|
|
|
|
|
def import_builtin_pages(json_file: str | Path, user=None):
|
|
"""
|
|
Import builtin pages
|
|
|
|
:param json_file: The json file which holds the data.
|
|
:type json_file: str | Path
|
|
:raises ValueError: If file does not exist or json_file is not a file.
|
|
:return: `True` if pages were successfully imported, `False` otherwise
|
|
:rvalue: bool
|
|
"""
|
|
if isinstance(json_file, str):
|
|
json_file = Path(json_file).resolve()
|
|
|
|
if not json_file.exists():
|
|
raise ValueError("File \"{json_file}\" does not exist!")
|
|
if not json_file.isfile():
|
|
raise ValueError("json_file needs to be a valid file!")
|
|
|
|
with open(json_file, "rt", encoding="utf-8") as ifile:
|
|
data = json.loads(ifile.read())
|
|
|
|
app = data['app']
|
|
prefix = data['prefix']
|
|
version = data['version']
|
|
|
|
page_path = json_file.parent
|
|
|
|
try:
|
|
bp = BuiltinPages.objects.get(app=app)
|
|
if version <= bp.version:
|
|
print("Page already imported, skipping!")
|
|
return False
|
|
|
|
for slug, spec in data['pages'].items():
|
|
filename = page_path / spec['file']
|
|
with open(filename, "rt", encoding="utf-8") as ifile:
|
|
content = ifile.read()
|
|
|
|
try:
|
|
p = Page.objects.get()
|
|
p.title = spec['title']
|
|
p.status_data = WikiPageStatus.from_string(spec['status']).value
|
|
p.content_type_data = WikiContentType.from_string(spec['content_type']).value,
|
|
p.content = content
|
|
p.author = user if user else get_tinywiki_default_user()
|
|
p.save()
|
|
except Page.DoesNotExist:
|
|
Page.objects.create(slug=slug,
|
|
title=spec['title'],
|
|
status_data=WikiPageStatus.from_string(spec['status']).value,
|
|
content_type_data=WikiContentType.from_string(spec['content_type']).value,
|
|
content=content,
|
|
author=user if user else get_tinywiki_default_user())
|
|
bp.prefix = prefix
|
|
bp.version = version
|
|
bp.save()
|
|
return True
|
|
except BuiltinPages.DoesNotExist:
|
|
for slug, spec in data['pages'].items():
|
|
filename = page_path / spec['file']
|
|
with open(filename, "rt", encoding="utf-8") as ifile:
|
|
content = ifile.read()
|
|
|
|
Page.objects.create(slug=slug,
|
|
title=spec['title'],
|
|
status_data=WikiPageStatus.from_string(spec['status']).value,
|
|
content_type_data=WikiContentType.from_string(spec['content_type']).value,
|
|
content=content,
|
|
author=user if user else get_tinywiki_default_user())
|
|
BuiltinPages.objects.create(app=app, prefix=prefix, version=version)
|
|
return True
|
|
|
|
|
|
def import_builtin_pages_from_zip(zip: str | Path, user=None):
|
|
"""
|
|
Import builtin pages
|
|
|
|
:param zip: The zip file which holds the data.
|
|
:type zip: str | Path
|
|
:raises ValueError: If file does not exist or json_file is not a file.
|
|
:return: `True` if pages were successfully imported, `False` otherwise
|
|
:rvalue: bool
|
|
"""
|
|
if isinstance(zip, str):
|
|
zip = Path(zip).resolve()
|
|
|
|
if not zip.exists():
|
|
raise ValueError(f"File \"{zip}\" does not exist!")
|
|
if not zip.isfile():
|
|
raise ValueError("zip needs to be a valid file!")
|
|
if not zipfile.is_zipfile(zip):
|
|
raise ValueError("zip needs to be a zip file!")
|
|
|
|
|
|
with zipfile.ZipFile(zip, "r") as zf:
|
|
with zf.open('pages.json') as json_file:
|
|
data = json.loads(json_file.read().decode('utf-8'))
|
|
|
|
app = data['app']
|
|
prefix = data['prefix']
|
|
version = data['version']
|
|
|
|
try:
|
|
bp = BuiltinPages.objects.get(app=app)
|
|
if version <= bp.version:
|
|
print("Page already imported, skipping!")
|
|
return False
|
|
|
|
for slug, spec in data['pages'].items():
|
|
with zf.open(spec['file']) as ifile:
|
|
content = ifile.read().decode('utf-8')
|
|
|
|
try:
|
|
p = Page.objects.get()
|
|
p.title = spec['title']
|
|
p.status_data = WikiPageStatus.from_string(spec['status']).value
|
|
p.content_type_data = WikiContentType.from_string(spec['content_type']).value,
|
|
p.content = content
|
|
p.author = user if user else get_tinywiki_default_user()
|
|
p.save()
|
|
except Page.DoesNotExist:
|
|
Page.objects.create(slug=slug,
|
|
title=spec['title'],
|
|
status_data=WikiPageStatus.from_string(spec['status']).value,
|
|
content_type_data=WikiContentType.from_string(spec['content_type']).value,
|
|
content=content,
|
|
author=user if user else get_tinywiki_default_user())
|
|
bp.prefix = prefix
|
|
bp.version = version
|
|
bp.save()
|
|
return True
|
|
except BuiltinPages.DoesNotExist:
|
|
for slug, spec in data['pages'].items():
|
|
with zf.open(spec['file'], "rt", encoding="utf-8") as ifile:
|
|
content = ifile.read()
|
|
|
|
Page.objects.create(slug=slug,
|
|
title=spec['title'],
|
|
status_data=WikiPageStatus.from_string(spec['status']).value,
|
|
content_type_data=WikiContentType.from_string(spec['content_type']).value,
|
|
content=content,
|
|
author=user if user else get_tinywiki_default_user())
|
|
BuiltinPages.objects.create(app=app, prefix=prefix, version=version)
|
|
return True
|
|
|
|
|
|
def import_builtin_images(json_file: str | Path, user=None):
|
|
if isinstance(json_file, str):
|
|
json_file = Path(json_file).resolve()
|
|
if not json_file.exists():
|
|
raise ValueError(f"File \"{json_file}\" does not exist!")
|
|
if not json_file.isfile():
|
|
raise ValueError("json_file needs to be a valid file!")
|
|
|
|
image_dir = json_file.parent
|
|
|
|
with open(json_file, "rt", encoding="utf-8") as ifile:
|
|
data = json.loads(ifile.read())
|
|
|
|
version = data['version']
|
|
app = data['app']
|
|
prefix = data['prefix']
|
|
|
|
try:
|
|
bi = BuiltinImages.objects.get(app=app)
|
|
if bi.version <= data['version']:
|
|
return False
|
|
|
|
for slug, spec in data['images'].items():
|
|
try:
|
|
img = Image.objects.get(slug=spec['slug'])
|
|
continue
|
|
except Image.DoesNotExist:
|
|
image_basename = spec['image']
|
|
image_filename = image_dir / spec.pop("image")
|
|
spec['slug'] = slug
|
|
spec['user'] = user if user else get_tinywiki_default_user()
|
|
|
|
img = Image(**spec)
|
|
with open(image_filename, "rb") as ifile:
|
|
img_file = ImageFile(ifile, image_basename)
|
|
img.image.save(image_basename, img_file)
|
|
img.save()
|
|
bi.version = version
|
|
bi.save()
|
|
return True
|
|
except BuiltinImages.DoesNotExist:
|
|
for slug, spec in data['images'].items():
|
|
spec = spec
|
|
image_basename = spec['image']
|
|
image_filename = image_dir / spec.pop("image")
|
|
spec['slug'] = slug
|
|
spec['user'] = user if user else get_tinywiki_default_user()
|
|
|
|
img = Image(**spec)
|
|
with open(image_filename, "rb") as ifile:
|
|
img_file = ImageFile(ifile, image_basename)
|
|
img.image.save(image_basename, img_file)
|
|
img.save()
|
|
|
|
BuiltinImages.objects.create(app=app, prefix=prefix, version=version)
|
|
return True
|
|
|
|
|
|
def import_builtin_images_from_zip(zip_file: str | Path, user=None):
|
|
if not isinstance(zip, Path):
|
|
zip_file = Path(zip).resolve()
|
|
|
|
if not zip_file.exists():
|
|
raise ValueError(f"File \"{zip_file}\" does not exist!")
|
|
if not zip_file.isfile():
|
|
raise ValueError("zip needs to be a valid file!")
|
|
if not zip_file.is_zipfile(zip_file):
|
|
raise ValueError("zip needs to be a zip file!")
|
|
|
|
with zipfile.ZipFile(zip_file, "r", encoding="utf-8") as zf:
|
|
data = json.loads(zf.open('images.json').read().decode('utf-8'))
|
|
|
|
version = data['version']
|
|
app = data['app']
|
|
prefix = data['prefix']
|
|
|
|
try:
|
|
bi = BuiltinImages.objects.get(app=app)
|
|
if bi.version <= data['version']:
|
|
return False
|
|
|
|
for slug, spec in data['images'].items():
|
|
try:
|
|
img = Image.objects.get(slug=spec['slug'])
|
|
continue
|
|
except Image.DoesNotExist:
|
|
image_basename = os.path.basename(spec['image'])
|
|
image_filename = spec.pop("image")
|
|
spec['slug'] = slug
|
|
spec['user'] = user if user else get_tinywiki_default_user()
|
|
|
|
img = Image(**spec)
|
|
with zf.open(image_filename) as ifile:
|
|
img_file = ImageFile(ifile, image_basename)
|
|
img.image.save(image_basename, img_file)
|
|
img.save()
|
|
bi.version = version
|
|
bi.save()
|
|
return True
|
|
except BuiltinImages.DoesNotExist:
|
|
for slug, spec in data['images'].items():
|
|
spec = spec
|
|
image_basename = os.path.basename(spec['image'])
|
|
image_filename = spec.pop("image")
|
|
spec['slug'] = slug
|
|
spec['user'] = user if user else get_tinywiki_default_user()
|
|
|
|
img = Image(**spec)
|
|
with zf.open(image_filename) as ifile:
|
|
img_file = ImageFile(ifile, image_basename)
|
|
img.image.save(image_basename, img_file)
|
|
img.save()
|
|
|
|
BuiltinImages.objects.create(app=app, prefix=prefix, version=version)
|
|
return True
|
|
|
|
|
|
def export_wiki_content(app: str,
|
|
filename,
|
|
prefix: str | None = None,
|
|
page_version: int = 0,
|
|
image_version: int = 0) -> bool:
|
|
prefix = prefix
|
|
try:
|
|
bp = BuiltinPages.objects.get(app=app)
|
|
if page_version < bp.version:
|
|
page_version = bp.version + 1
|
|
if not prefix:
|
|
prefix = bp.prefix
|
|
except BuiltinPages.DoesNotExist:
|
|
bp = None
|
|
|
|
try:
|
|
bi = BuiltinImages.objects.get(app=app)
|
|
if image_version < bi.version:
|
|
image_version = bi.version + 1
|
|
if not prefix:
|
|
prefix = bp.prefix
|
|
except BuiltinImages.DoesNotExist:
|
|
bi = None
|
|
|
|
if not prefix:
|
|
raise RuntimeError("No slug prefix! Can not export!")
|
|
|
|
pages = Page.objects.filter(slug__startswith=prefix)
|
|
images = Image.objects.filter(slug__startswith=prefix)
|
|
|
|
if not pages and not images:
|
|
return False
|
|
|
|
with zipfile.ZipFile(filename, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
|
if pages:
|
|
|
|
pages_data = {
|
|
'app': app,
|
|
'prefix': prefix,
|
|
'version': page_version,
|
|
'pages': {}
|
|
}
|
|
|
|
for p in pages:
|
|
if WikiContentType.BBCODE == p.content_type:
|
|
extension = 'bbcode'
|
|
else:
|
|
extension = 'md'
|
|
page_file = f"pages/{p.slug}.{extension}"
|
|
pages_data['pages'][p.slug] = {
|
|
'title': p.title,
|
|
'content_type': p.content_type.value,
|
|
'status': p.status.value,
|
|
'file': page_file,
|
|
}
|
|
zf.writestr(page_file, p.content)
|
|
zf.writestr('pages.json', json.dumps(pages_data, ensure_ascii=False, indent=4))
|
|
if bp:
|
|
bp.version = page_version
|
|
bp.save()
|
|
else:
|
|
BuiltinPages.objects.create(app=app, prefix=prefix, version=page_version)
|
|
|
|
if images:
|
|
images_data = {
|
|
'app': app,
|
|
'prefix': prefix,
|
|
'version': image_version,
|
|
'images': {}
|
|
}
|
|
for i in images:
|
|
if not os.path.isfile(i.image.path):
|
|
continue
|
|
|
|
arcname = f"images/{os.path.basename(i.image.path)}"
|
|
images_data['images'][i.slug] = {
|
|
'slug': i.slug,
|
|
'alt': i.alt,
|
|
'file': arcname,
|
|
'description': i.description,
|
|
}
|
|
zf.write(i.image.path, arcname)
|
|
zf.writestr('images.json', json.dumps(images_data, ensure_ascii=False, indent=4))
|
|
if bi:
|
|
bi.version = image_version
|
|
bi.save()
|
|
else:
|
|
BuiltinImages.objects.create(app=app, prefix=prefix, version=image_version)
|
|
return True
|
|
|
|
|
|
def export_tinywiki_wiki_content(filename=None):
|
|
if filename is None:
|
|
filename = Path(django_settings.MEDIA_ROOT) / "tinywiki-tinywiki.zip"
|
|
export_wiki_content('tinywiki', filename, 'tw-')
|