Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ test_job:
script:
- echo "$GL_URL"
- echo "$GH_URL"
- python manage.py migrate
# - echo "$CI_PERSONAL_TOKEN_KEY_GL"
- python manage.py test tests

Expand Down
Binary file added db.sqlite3
Binary file not shown.
5 changes: 5 additions & 0 deletions meta_creator/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django import forms
from captcha.fields import CaptchaField

class CaptchaForm(forms.Form):
captcha = CaptchaField()
28 changes: 28 additions & 0 deletions meta_creator/templates/meta_creator/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,34 @@ <h6 class="custom-tooltip">
>{{ error_message_token }}</span
>
{% endif %}
<div class="captcha-box">
<h6 for="id_captcha_1" class="custom-tooltip">
Captcha Check
<span class="tooltip-text">
CAPTCHA is a security system used to prevent spam and abuse by
distinguishing human users from automated bots.
</span>
<i class="fa fa-info-circle" aria-hidden="true"></i>
{% for message in messages %}<span
id="captcha-error"
class="captcha-error"
>{{ message }}</span
>{% endfor %}
</h6>
<!-- Captcha image box + refresh button -->
<div class="captcha-image-wrapper">
{{ captcha_form.captcha}}
<button
type="button"
class="captcha-refresh-btn"
id="captcha-refresh"
title="Refresh Captcha">
&#x21bb;
</button>
</div>

<!-- Hidden + text input -->
</div>
<div class="d-grid col-4 mx-auto">
<button
id="submitBtn"
Expand Down
115 changes: 66 additions & 49 deletions meta_creator/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@
from requests.exceptions import ConnectTimeout, ReadTimeout, RequestException
from .metadata_extractor import data_extraction
from .validate_jsonLD import validate_codemeta
from .forms import CaptchaForm
from django.shortcuts import render, redirect
from django.contrib import messages

class IndexView(TemplateView):
template_name = 'meta_creator/index.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['captcha_form'] = CaptchaForm() # ← add this
return context


# navigation to homepage and information page_based on requiremment analysis
Expand All @@ -42,56 +49,66 @@ def index(request):
HttpResponse: The HTTP response object.

"""
try:
result = data_extraction(request)

if not result.get('success'):
errors = result.get('errors')

# Check if errors is a list or a string and format accordingly
if isinstance(errors, list):
error_messages = ['Error in extraction:'] + errors
else:
error_messages = ['Error in extraction:', errors]
return render(request, 'meta_creator/error.html', {
'error_message': "; ".join(error_messages)
captcha_form = CaptchaForm(request.POST or None)

# Handle GET request - just show the form
if request.method == "GET":
return render(request, 'meta_creator/index.html', {
"captcha_form": captcha_form,
})

# Handle POST request
if request.method == "POST":

if not captcha_form.is_valid():
messages.error(request, "Invalid Captcha. Please try again.")
return redirect('meta_creator:index')

# Captcha is valid, proceed with extraction
try:
result = data_extraction(request)

if not result.get('success'):
errors = result.get('errors')
if isinstance(errors, list):
error_messages = ['Error in extraction:'] + errors
else:
error_messages = ['Error in extraction:', errors]
return render(request, 'meta_creator/error.html', {
'error_message': "; ".join(error_messages)
})



my_json_str = {}
# Extract metadata
extracted_metadata, description_metadata, type_metadata, joined_metadata = result['metadata']
# Validate the JSON data
is_valid_jsonld = validate_codemeta(joined_metadata)
if is_valid_jsonld:
validation_result = "The JSON data is a valid JSON-LD Codemeta object"
else:
validation_result = "The JSON data is not a valid JSON-LD Codemeta object"
# Convert the dictionary to JSON
my_json_str = json.dumps(joined_metadata, indent=4)
template = loader.get_template('meta_creator/showdata.html')
return HttpResponse(template.render({
"type_metadata": type_metadata,
"description_metadata":description_metadata,
"extracted_metadata":extracted_metadata,
"my_json_str": my_json_str,
"from_showdata": True,
extracted_metadata, description_metadata, type_metadata, joined_metadata = result['metadata']
is_valid_jsonld = validate_codemeta(joined_metadata)

if is_valid_jsonld:
validation_result = "The JSON data is a valid JSON-LD Codemeta object"
else:
validation_result = "The JSON data is not a valid JSON-LD Codemeta object"

my_json_str = json.dumps(joined_metadata, indent=4)
template = loader.get_template('meta_creator/showdata.html')
return HttpResponse(template.render({
"type_metadata": type_metadata,
"description_metadata": description_metadata,
"extracted_metadata": extracted_metadata,
"my_json_str": my_json_str,
"from_showdata": True,
}, request))

except ConnectTimeout:
error_message = "Connection timed out."
except ReadTimeout:
error_message = "Read operation timed out."
except RequestException:
error_message = "Error fetching data from GitHub API"
except ConnectionError as conn_error:
error_message = f"Could not establish a connection: {conn_error}"
except PermissionDenied:
error_message = "CSRF Error: This action is not allowed."
return HttpResponseForbidden(error_message)
except Exception as unexpected_exception:
error_message = f"An unexpected error occurred: {str(unexpected_exception)}"
return HttpResponseServerError(error_message)

return render(request, 'meta_creator/error.html', {'error_message': error_message})
except ConnectTimeout:
error_message = "Connection timed out."
except ReadTimeout:
error_message = "Read operation timed out."
except RequestException:
error_message = "Error fetching data from GitHub API"
except ConnectionError as conn_error:
error_message = f"Could not establish a connection: {conn_error}"
except PermissionDenied:
error_message = "CSRF Error: This action is not allowed."
return HttpResponseForbidden(error_message)
except Exception as unexpected_exception:
error_message = f"An unexpected error occurred: {str(unexpected_exception)}"
return HttpResponseServerError(error_message)

return render(request, 'meta_creator/error.html', {'error_message': error_message})
13 changes: 12 additions & 1 deletion meta_tool/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import os
import environs
import sys
# from configobj import ConfigObj

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
Expand Down Expand Up @@ -45,6 +46,7 @@
'django_jsonforms',
'meta_creator',
'django.contrib.staticfiles',
'captcha',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -81,7 +83,13 @@
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}

}


# Password validation
Expand Down Expand Up @@ -127,3 +135,6 @@
]
DEBUG = True
JSONFORMS_SCHEMA_DIR = 'static/metajsons/'

if 'test' in sys.argv:
CAPTCHA_TEST_MODE = True
3 changes: 2 additions & 1 deletion meta_tool/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
path(
'meta_creator/',
include('meta_creator.urls', namespace='meta_creator')
)
),
path('captcha/', include('captcha.urls')),
]
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ environs==9.3.5
marshmallow>=3.26.2,<4
pyyaml>=6.0
pyld==2.0.3
django-simple-captcha==0.6.0

# Git integration libraries
python-gitlab==3.13.0
Expand Down
69 changes: 68 additions & 1 deletion static/foundation/css/foundation.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ button.ExData {
border-radius: 4px;
cursor: pointer;
font-weight: bold;
margin-top: 3.5rem;
margin-top: 1.5rem;
}

button.TrySMECS {
Expand Down Expand Up @@ -174,7 +174,74 @@ button#new-url-extraction-page:hover {
cursor: pointer;
border: 1px solid #4ba0af;
}
/******captcha******/
/* Captcha error */
.captcha-box {
display: flex;
flex-direction: column;
}
.captcha-error {
color: #e53935;
font-size: 0.875rem;
font-weight: 500;
padding: 6px 12px;
}

/* Captcha image box */
.captcha-image-wrapper {
display: flex;
align-items: center;
gap: 12px;
margin: 8px 0;
}

.captcha-image-wrapper img {
border: 2px solid #ccc;
border-radius: 6px;
background: #f9f9f9;
width: auto;
height: 60px;
object-fit: contain;
display: block;
}

/* Refresh button */
.captcha-refresh-btn {
background: none;
border: 1px solid #055f82;
border-radius: 4px;
cursor: pointer;
font-size: 1.5rem;
color: #055f82;
transition: all 0.2s;
}

.captcha-refresh-btn:hover {
background: #f0f0f0;
border-color: #333;
color: #333;
}
.captcha_label {
margin: 0;
padding: 0;
font-size: o;
}

/* Text input styling */
#id_captcha_1 {
padding: 6px 10px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 0.95rem;
display: block;
}

/* Hide the default label Django renders */
label[for="id_captcha_1"] {
display: block;
font-weight: 700;
font-size: 0.87rem;
}
/************ Tool Tip Styles ************/
.tooltip-container {
display: flex;
Expand Down
3 changes: 2 additions & 1 deletion static/foundation/js/vendor/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { setupForm } from "./form-utils.js";
import { initializeTaggingFields } from "./tagging.js";
import { setupTables } from "./table-utils.js";
import { setupDownload } from "./download.js";
import { setupUI, loadpage } from "./ui.js";
import { setupUI, loadpage, initCaptcha } from "./ui.js";
import { initializeDynamicDropdowns } from "./dropdown-utils.js";
import { setMandatoryFieldsFromSchema } from "./schema-utils.js";
// Entry point: called when DOM is fully loaded
document.addEventListener("DOMContentLoaded", () => {
initCaptcha();
loadpage();
initializeTaggingFields();
setupTables();
Expand Down
Loading
Loading