diff --git a/backend/.gitignore b/backend/.gitignore
index 5fcd1f6..1fbbaea 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -15,6 +15,7 @@ deploy
media
static
templates
+start_editor.sh
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
diff --git a/backend/apimanager/publish_methods.py b/backend/apimanager/publish_methods.py
index 0a05ac8..74174b0 100644
--- a/backend/apimanager/publish_methods.py
+++ b/backend/apimanager/publish_methods.py
@@ -11,18 +11,16 @@ from .dialogue_box import (
)
from .publish_methods_github import (
- create_404_page,
git_existing_repo_setup,
github_init,
github_pages_deploy
-
)
deployment_methods = {
- "server_deploy": {
+ "server": {
"name": "Server Deploy"
},
- "github_deploy": {
+ "ghpages": {
"name": "Github Deploy"
}
}
@@ -30,12 +28,7 @@ deployment_methods = {
def server_deploy():
try:
- copy_content(
- settings.DEPLOY_CONFIG["EDITOR_DATA_LOCATION"],
- f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/server/data',
- 'folder',
- 'remove_and_copy'
- )
+ copy_data_and_html('server')
return {'message': 'Server deployment successful', 'status': status.HTTP_200_OK}
except Exception as e:
print(f"An error occurred: {str(e)}")
@@ -60,18 +53,9 @@ def github_deploy():
}
deploy_location = settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]+'/ghpages'
-
- create_404_page(deploy_location)
- copy_content(
- settings.DEPLOY_CONFIG["EDITOR_DATA_LOCATION"],
- f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/ghpages/data',
- 'folder',
- 'remove_and_copy'
- )
-
+ copy_data_and_html('ghpages')
if not os.path.exists(f'{deploy_location}/.git'):
try:
-
existing_repo = draw_dialogue_box(
'Github Deploy',
'Do you have an existing repository with Rangolio on github?',
@@ -94,3 +78,24 @@ def github_deploy():
except Exception as e:
print(f"An error occurred: {str(e)}")
return {'message': str(e), 'status': status.HTTP_500_INTERNAL_SERVER_ERROR}
+
+
+def copy_data_and_html(deploy_type):
+ copy_content(
+ settings.DEPLOY_CONFIG["EDITOR_DATA_LOCATION"],
+ f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/{deploy_type}/data',
+ 'folder',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{settings.DEPLOY_CONFIG["EDITOR_HTML_LOCATION"]}/categories',
+ f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/{deploy_type}/categories',
+ 'folder',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{settings.DEPLOY_CONFIG["EDITOR_HTML_LOCATION"]}/blog',
+ f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/{deploy_type}/blog',
+ 'folder',
+ 'remove_and_copy'
+ )
diff --git a/backend/apimanager/publish_methods_github.py b/backend/apimanager/publish_methods_github.py
index f9abf84..c4f576a 100644
--- a/backend/apimanager/publish_methods_github.py
+++ b/backend/apimanager/publish_methods_github.py
@@ -4,11 +4,14 @@ import shutil
import subprocess
import urllib.parse
+from .utilities import (
+ copy_content
+)
+
from .dialogue_box import (
draw_dialogue_box
)
-
def github_init(deploy_location, git_commands):
user_details_defined = git_check_user_details(deploy_location, git_commands)
if not user_details_defined:
@@ -74,15 +77,44 @@ def git_check_user_details(deploy_location, git_commands):
def git_update_viewable_ui(deploy_location, dist_folder_name, build_frontend=False):
shutil.move(deploy_location, f'{deploy_location}.temp')
+
if build_frontend:
subprocess.run(["npm", 'run', 'build:ghpages'], cwd=settings.DEPLOY_CONFIG["VIEWABLE_UI_LOCATION"], check=True,
text=True, capture_output=True)
+
shutil.move(f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/{dist_folder_name}', f'{deploy_location}')
- shutil.copy(f'{deploy_location}.temp/index.html', deploy_location)
- shutil.copy(f'{deploy_location}.temp/404.html', deploy_location)
- shutil.copytree(f'{deploy_location}.temp/assets', f'{deploy_location}/assets', dirs_exist_ok=True)
- if os.path.exists(f'{deploy_location}.temp/data'):
- shutil.copytree(f'{deploy_location}.temp/data', f'{deploy_location}/data', dirs_exist_ok=True)
+
+ copy_content(
+ f'{deploy_location}.temp/index.html',
+ deploy_location,
+ 'file',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{deploy_location}.temp/assets',
+ f'{deploy_location}/assets',
+ 'folder',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{deploy_location}.temp/data',
+ f'{deploy_location}/data',
+ 'folder',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{deploy_location}.temp/categories',
+ f'{deploy_location}/categories',
+ 'folder',
+ 'remove_and_copy'
+ )
+ copy_content(
+ f'{deploy_location}.temp/blog',
+ f'{deploy_location}/blog',
+ 'folder',
+ 'remove_and_copy'
+ )
+
shutil.rmtree(f'{deploy_location}.temp')
@@ -124,34 +156,3 @@ def github_pages_deploy(deploy_location, git_commands):
subprocess.run(git_commands["git_add"], cwd=deploy_location, check=True, text=True, capture_output=True)
subprocess.run(git_commands["git_commit"], cwd=deploy_location, check=True, text=True, capture_output=True)
subprocess.run(git_commands["git_push"], cwd=deploy_location, check=True, text=True, capture_output=True)
-
-
-def create_404_page(deploy_location):
- html_content = """
-
-
-
-
- Rangoio
-
-
-
-
-
- """
-
- with open(f'{deploy_location}/404.html', 'w') as file:
- file.write(html_content)
-
- print("404 page created successfully.")
-
\ No newline at end of file
diff --git a/backend/apimanager/publish_views.py b/backend/apimanager/publish_views.py
index 3e1ee33..8ad030f 100644
--- a/backend/apimanager/publish_views.py
+++ b/backend/apimanager/publish_views.py
@@ -7,6 +7,7 @@ from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from django.core.files.base import ContentFile
+from bs4 import BeautifulSoup
from .custom_storage import (
CustomStorage
@@ -38,55 +39,59 @@ class Publish(APIView):
def get(self, request, deploy_type, format=None):
if deploy_type not in deployment_methods:
return Response(status=status.HTTP_404_NOT_FOUND)
+ json_storage_location = settings.DEPLOY_CONFIG["EDITOR_DATA_LOCATION"]
+ html_storage_location = settings.DEPLOY_CONFIG["EDITOR_HTML_LOCATION"]
- storage = CustomStorage()
- self.delete_old_data()
- self.create_json(storage)
+ json_storage = CustomStorage(json_storage_location)
+ html_storage = CustomStorage(html_storage_location)
+
+ self.delete_old_data(json_storage_location)
+ self.delete_old_data(html_storage_location)
+
+ self.create_json_and_html(json_storage, html_storage, deploy_type)
response = self.execute_deploy(deploy_type)
return Response(response['message'], response['status'])
- def delete_old_data(self):
- data_directory = 'deploy/data'
-
+ def delete_old_data(self, data_directory):
if os.path.exists(data_directory):
shutil.rmtree(data_directory)
print(f"The directory {data_directory} has been deleted.")
else:
print(f"The directory {data_directory} does not exist.")
- def create_json(self, storage):
- self.create_user_data_json(UserData.objects.first(), storage)
- self.create_theme_data_json(UserData.objects.first(), storage)
- self.create_category_data_json(Category, storage)
- self.create_blog_data_json(Blog.objects.all(), storage)
+ def create_json_and_html(self, json_storage, html_storage, deploy_type):
+ self.create_user_data_json(UserData.objects.first(), json_storage)
+ self.create_theme_data_json(UserData.objects.first(), json_storage)
+ self.create_category_data_json_and_html(Category, json_storage, html_storage, deploy_type)
+ self.create_blog_data_json_and_html(Blog.objects.all(), json_storage, html_storage, deploy_type, UserData.objects.first())
copy_content(
settings.DEPLOY_CONFIG["EDITOR_MEDIA_LOCATION"],
settings.DEPLOY_CONFIG["EDITOR_DATA_LOCATION"],
'folder',
)
- def create_user_data_json(self, instance, storage):
+ def create_user_data_json(self, instance, json_storage):
json_content = {
"name": instance.name,
"introContent": self.sanitize_media_link(instance.intro_content, 'content_media'),
"profilePhoto": self.sanitize_media_link(instance.profile_photo),
"builtWith": instance.built_with
}
- self.save_json(json_content, 'shared/user-data.json', storage)
+ self.save_json(json_content, 'shared/user-data.json', json_storage)
- def create_theme_data_json(self, instance, storage):
+ def create_theme_data_json(self, instance, json_storage):
json_content = {
"defaultTheme": instance.default_theme,
"darkTheme": ast.literal_eval(instance.dark_theme),
"lightTheme": ast.literal_eval(instance.light_theme),
}
- self.save_json(json_content, 'shared/theme-config.json', storage)
+ self.save_json(json_content, 'shared/theme-config.json', json_storage)
- def create_category_data_json(self, model_instance, storage):
+ def create_category_data_json_and_html(self, model_instance, json_storage, html_storage, deploy_type):
categories = []
instance_objects = model_instance.objects.all()
if not instance_objects.exists():
- self.save_json([], 'category/category-metadata.json', storage)
+ self.save_json([], 'category/category-metadata.json', json_storage)
else:
for eachInstance in instance_objects:
instance_data = {
@@ -98,10 +103,12 @@ class Publish(APIView):
"featuredBlog": eachInstance.featured_id
}
categories.append(instance_data)
- self.create_instance_data(instance_data, model_instance.objects.get(category_id=eachInstance.category_id), storage)
- self.save_json(categories, 'category/category-metadata.json', storage)
+ self.create_instance_data(instance_data, model_instance.objects.get(category_id=eachInstance.category_id), json_storage)
+ self.save_json(categories, 'category/category-metadata.json', json_storage)
+ self.save_html(categories, 'categories', html_storage, deploy_type)
- def create_blog_data_json(self, instance, storage):
+ def create_blog_data_json_and_html(self, instance, json_storage, html_storage, deploy_type, UserDataInstance):
+ blogs = []
if not instance.exists():
pass
else:
@@ -115,13 +122,15 @@ class Publish(APIView):
"parentCategory": str(eachBlog.parent_category.category_id),
"contentBody": self.sanitize_media_link(eachBlog.content_body, 'content_media')
}
- self.save_json(instance_data, f'blog/{instance_data["id"]}/blog-data.json', storage)
+ blogs.append(instance_data)
+ self.save_json(instance_data, f'blog/{instance_data["id"]}/blog-data.json', json_storage)
+ self.save_html(blogs, 'blog', html_storage, deploy_type, UserDataInstance)
- def create_instance_data(self, instance_data, blogs_by_category_instance, storage):
+ def create_instance_data(self, instance_data, blogs_by_category_instance, json_storage):
instance_data["blogMetadata"]=[]
blogs = blogs_by_category_instance.blogs.all()
if not blogs.exists():
- self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', storage)
+ self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', json_storage)
else:
for eachBlog in blogs:
instance_data["blogMetadata"].append({
@@ -132,7 +141,7 @@ class Publish(APIView):
"tagLine": eachBlog.tagline,
"parentCategory": instance_data["id"]
})
- self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', storage)
+ self.save_json(instance_data, f'category/{instance_data["id"]}/category-data.json', json_storage)
def save_json(self, json_content, file_name, storage):
data_json = json.dumps(json_content, indent=2)
@@ -140,6 +149,41 @@ class Publish(APIView):
storage.delete(file_name)
storage.save(file_name, ContentFile(data_json.encode('utf-8')))
+ def save_html(self, json_content, resource_type, storage, deploy_type, UserDataInstance=None):
+ html_file = open(f'{settings.DEPLOY_CONFIG["DEPLOY_LOCATION"]}/{deploy_type}/index.html', "r")
+ html_file_content = html_file.read()
+ html_soup = BeautifulSoup(html_file_content, 'lxml')
+
+ html_soup.title.string = resource_type
+ meta_robots = html_soup.new_tag('meta', attrs={'name': 'robots', 'content': 'index, follow'})
+ html_soup.head.append(meta_robots)
+
+ storage.save(f'{resource_type}/index.html', ContentFile(str(html_soup).encode('utf-8')))
+
+ for eachEntry in json_content:
+ html_soup = BeautifulSoup(html_file_content, 'lxml')
+ html_soup.title.string = eachEntry['name']
+ meta_description = html_soup.new_tag('meta', attrs={'name': 'description', 'content': f'{eachEntry["name"]} {eachEntry["description"]} {eachEntry["tagLine"]}'})
+ meta_robots = html_soup.new_tag('meta', attrs={'name': 'robots', 'content': 'index, follow'})
+ meta_language = html_soup.new_tag('meta', attrs={'name': 'language', 'content': 'english'})
+
+ meta_og_description = html_soup.new_tag('meta', attrs={'name': 'og:description', 'content': f'{eachEntry["name"]} {eachEntry["description"]} {eachEntry["tagLine"]}'})
+ meta_og_title = html_soup.new_tag('meta', attrs={'name': 'og:title', 'content': eachEntry['name']})
+ meta_og_type = html_soup.new_tag('meta', attrs={'name': 'og:type', 'content': 'website'})
+
+ html_soup.head.append(meta_description)
+ html_soup.head.append(meta_robots)
+ html_soup.head.append(meta_language)
+ html_soup.head.append(meta_og_description)
+ html_soup.head.append(meta_og_title)
+ html_soup.head.append(meta_og_type)
+
+ if UserDataInstance:
+ meta_author = html_soup.new_tag('meta', attrs={'name': 'author', 'content': UserDataInstance.name})
+ html_soup.head.append(meta_author)
+
+ storage.save(f'{resource_type}/{eachEntry["id"]}/index.html', ContentFile(str(html_soup).encode('utf-8')))
+
def sanitize_media_link(self, string, content_type='element'):
if not string:
return ''
@@ -154,9 +198,9 @@ class Publish(APIView):
'status': status.HTTP_500_INTERNAL_SERVER_ERROR
}
- if deploy_type == "server_deploy":
+ if deploy_type == "server":
response = server_deploy()
- if deploy_type == "github_deploy":
+ if deploy_type == "ghpages":
response = github_deploy()
return response
diff --git a/backend/backend/settings.py b/backend/backend/settings.py
index 1419ecf..99891d4 100644
--- a/backend/backend/settings.py
+++ b/backend/backend/settings.py
@@ -44,6 +44,7 @@ INSTALLED_APPS = [
DEPLOY_CONFIG = {
"VIEWABLE_UI_LOCATION": os.path.join(BASE_DIR, '../frontend/viewable-ui'),
"DEPLOY_LOCATION": os.path.join(BASE_DIR, '../frontend/viewable-ui/dist'),
+ "EDITOR_HTML_LOCATION": os.path.join(BASE_DIR, 'deploy/html'),
"EDITOR_DATA_LOCATION": os.path.join(BASE_DIR, 'deploy/data'),
"EDITOR_MEDIA_LOCATION": os.path.join(BASE_DIR, 'media/data')
}
diff --git a/backend/requirements.txt b/backend/requirements.txt
index bc2a09c..2a7b902 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -1,13 +1,16 @@
asgiref==3.8.1
+beautifulsoup4==4.12.3
bottle==0.12.25
Django==5.0.6
djangorestframework==3.15.1
gunicorn==22.0.0
+lxml==5.2.2
packaging==24.0
pillow==10.3.0
proxy_tools==0.1.0
PyQt6==6.7.0
PyQt6-Qt6==6.7.1
PyQt6-sip==13.6.0
+soupsieve==2.5
sqlparse==0.5.0
typing_extensions==4.12.2
diff --git a/frontend/viewable-ui/vite.config.js b/frontend/viewable-ui/vite.config.js
index 5a4872b..9cf974f 100644
--- a/frontend/viewable-ui/vite.config.js
+++ b/frontend/viewable-ui/vite.config.js
@@ -6,16 +6,7 @@ import eslint from 'vite-plugin-eslint';
export default defineConfig({
plugins: [
react(),
- eslint(),
- process.env.BUILD_ENV === 'ghpages' ? {
- name: 'inject-ghpages-fix',
- transformIndexHtml(html) {
- return html.replace(
- '',
- ''
- );
- }
- } : ''
+ eslint()
],
server: {},
build: {