mirror of
https://github.com/Labelbase/Labelbase.git
synced 2026-08-18 13:09:04 +02:00
re-added labellabor
This commit is contained in:
parent
a4f9389d28
commit
a7c9442aee
8 changed files with 1246 additions and 0 deletions
0
django/labellabor/__init__.py
Normal file
0
django/labellabor/__init__.py
Normal file
16
django/labellabor/asgi.py
Normal file
16
django/labellabor/asgi.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
ASGI config for labellabor project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "labellabor.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
48
django/labellabor/make_config.py
Normal file
48
django/labellabor/make_config.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import string
|
||||
import secrets
|
||||
import configparser
|
||||
import time
|
||||
|
||||
|
||||
|
||||
def generate_random_string(length):
|
||||
# Exclude curly braces '{}' from the pool of characters
|
||||
characters = string.ascii_letters + string.digits
|
||||
return ''.join(secrets.choice(characters) for _ in range(length))
|
||||
|
||||
|
||||
def generate_config_file(config_file_path="config.ini"):
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
# Generate random values for password and secret_key with specified lengths
|
||||
dj_secret_key = generate_random_string(50)
|
||||
|
||||
# Set the values in the configuration file
|
||||
config['internal'] = {
|
||||
'secret_key': '{}'.format(dj_secret_key),
|
||||
'proj_name': 'labelbase',
|
||||
'crypto_salt': 'labelbase_',
|
||||
'allowed_host': '*',
|
||||
'debug': True,
|
||||
'current_timestamp_seconds': int(time.time())
|
||||
}
|
||||
|
||||
config['database'] = {
|
||||
'name': 'labelbase',
|
||||
'user': 'ulabelbase',
|
||||
'password': 'vrZvZmX6Kp16B9tTa8JAA4RtAkWEhi',
|
||||
# 'host': '127.0.0.1'
|
||||
}
|
||||
|
||||
# Create the configuration file and write the values
|
||||
with open(config_file_path, 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Check if the config.ini file exists
|
||||
if not os.path.isfile(config_file_path):
|
||||
generate_config_file()
|
||||
else:
|
||||
print("{} already exists.".format(config_file_path))
|
||||
229
django/labellabor/settings.py
Normal file
229
django/labellabor/settings.py
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
import os
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
from pathlib import Path
|
||||
from configparser import RawConfigParser
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
PROJECT_PATH = BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
proj_config = RawConfigParser()
|
||||
config_file_path = "{}/config.ini".format(PROJECT_PATH)
|
||||
try:
|
||||
if proj_config.read(config_file_path) == []:
|
||||
from .make_config import generate_config_file
|
||||
if not os.path.isfile(config_file_path):
|
||||
print("creating config file, here: {}".format(config_file_path))
|
||||
generate_config_file(config_file_path)
|
||||
assert proj_config.read(config_file_path) == []
|
||||
except AssertionError:
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured(
|
||||
"Configuration file {} not found!".format(config_file_path)
|
||||
)
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = proj_config.get("internal", "secret_key")
|
||||
CRYPTOGRAPHY_SALT = proj_config.get("internal", "crypto_salt")
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = proj_config.getboolean("internal", "debug")
|
||||
if DEBUG:
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
else:
|
||||
ALLOWED_HOSTS = [proj_config.get("internal", "allowed_host")]
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn="https://3b833ae08ccc4ff68793e961fff4921c@o4504646963232768.ingest.sentry.io/4504646967361536",
|
||||
integrations=[
|
||||
DjangoIntegration(),
|
||||
],
|
||||
# Set traces_sample_rate to 1.0 to capture 100%
|
||||
# of transactions for performance monitoring.
|
||||
# We recommend adjusting this value in production.
|
||||
traces_sample_rate=1.0,
|
||||
# If you wish to associate users to errors (assuming you are using
|
||||
# django.contrib.auth) you may enable sending PII data.
|
||||
send_default_pii=False,
|
||||
)
|
||||
sentry_sdk.set_tag("version", "0.23.1")
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '{levelname} {asctime} {module} {message}',
|
||||
'style': '{',
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': './labelbase.log',
|
||||
'maxBytes': 1024 * 1024 * 5, # 5 MB
|
||||
'backupCount': 5, # Keep 5 backup files
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'labelbase': {
|
||||
'handlers': ['file'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Application definition
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
# 'django.contrib.sessions', # NOTE: We use "user_sessions"
|
||||
"user_sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"two_factor",
|
||||
"two_factor.plugins.phonenumber",
|
||||
"django_otp",
|
||||
"django_otp.plugins.otp_static",
|
||||
"django_otp.plugins.otp_totp",
|
||||
"labelbase",
|
||||
"userprofile",
|
||||
"bootstrapform",
|
||||
"cryptography",
|
||||
"rest_framework",
|
||||
"rest_framework.authtoken",
|
||||
"sekizai",
|
||||
"importer",
|
||||
"finances",
|
||||
"background_task",
|
||||
"connectrum",
|
||||
]
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
#"django.middleware.cache.UpdateCacheMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django_otp.middleware.OTPMiddleware",
|
||||
#"django.middleware.cache.FetchFromCacheMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
|
||||
#CACHES = {
|
||||
# 'default': {
|
||||
# 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
# 'LOCATION': 'labelbase-snowflake',
|
||||
# }
|
||||
#}
|
||||
|
||||
ROOT_URLCONF = "labellabor.urls"
|
||||
|
||||
LOGIN_URL = "two_factor:login"
|
||||
|
||||
LOGIN_REDIRECT_URL = "two_factor:profile"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [os.path.join(PROJECT_PATH, "templates")],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"sekizai.context_processors.sekizai",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
CURRENCIES = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY']
|
||||
|
||||
|
||||
WSGI_APPLICATION = "labellabor.wsgi.application"
|
||||
|
||||
TWO_FACTOR_REMEMBER_COOKIE_AGE = 60 * 60 * 24 * 14
|
||||
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"NAME": proj_config.get("database", "name"),
|
||||
"USER": proj_config.get("database", "user"),
|
||||
"OPTIONS": {"charset": "utf8mb4"},
|
||||
"PASSWORD": proj_config.get("database", "password"),
|
||||
'HOST': 'localhost',
|
||||
'PORT': 3306,
|
||||
}
|
||||
}
|
||||
|
||||
TWO_FACTOR_WEBAUTHN_RP_NAME = "labelbase.space"
|
||||
|
||||
SESSION_ENGINE = "user_sessions.backends.db"
|
||||
|
||||
REST_FRAMEWORK = {"DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema"}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-FILE_UPLOAD_HANDLERS
|
||||
FILE_UPLOAD_HANDLERS = [
|
||||
"django.core.files.uploadhandler.MemoryFileUploadHandler",
|
||||
"django.core.files.uploadhandler.TemporaryFileUploadHandler",
|
||||
]
|
||||
250
django/labellabor/urls.py
Normal file
250
django/labellabor/urls.py
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.views import LogoutView
|
||||
from django.urls import include, path
|
||||
from two_factor.urls import urlpatterns as tf_urls
|
||||
from labelbase.api import LabelAPIView, LabelbaseAPIView
|
||||
from rest_framework.documentation import include_docs_urls
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from userprofile.views import (ProfileView,
|
||||
ProfileAvatarUpdateView,
|
||||
ProfileCurrencyUpdateView)
|
||||
from userprofile.views import APIKeyView
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
from .views import (
|
||||
LabelbaseView,
|
||||
LabelbaseViewActionView,
|
||||
LabelbaseMergeView,
|
||||
LabelbaseDeleteView,
|
||||
LabelDeleteView,
|
||||
TermsView,
|
||||
HomeView,
|
||||
RegistrationCompleteView,
|
||||
LabelUpdateView,
|
||||
PrivacyView,
|
||||
RegistrationView,
|
||||
LabelbaseFormView,
|
||||
LabelbaseUpdateView,
|
||||
FaqView,
|
||||
AboutView,
|
||||
EncryptionView,
|
||||
InteroperationalView,
|
||||
ExportLabelsView,
|
||||
#StatsAndKPIView,
|
||||
TreeMapsView,
|
||||
FixAndMergeLabelsView,
|
||||
LabelbaseDatatableView,
|
||||
LabelbasePortfolioView,
|
||||
)
|
||||
|
||||
from importer.views import upload_labels
|
||||
from exporter.views import stream_labels_as_jsonl
|
||||
from django.contrib.auth import views as auth_views
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"api/v0/labelbase/",
|
||||
LabelbaseAPIView.as_view()
|
||||
),
|
||||
path(
|
||||
"api/v0/labelbase/<int:id>/",
|
||||
LabelbaseAPIView.as_view()
|
||||
),
|
||||
path(
|
||||
"api/v0/labelbase/<int:labelbase_id>/label/",
|
||||
LabelAPIView.as_view()
|
||||
),
|
||||
path(
|
||||
"api/v0/labelbase/<int:labelbase_id>/label/<int:id>/",
|
||||
LabelAPIView.as_view()
|
||||
),
|
||||
path(
|
||||
"api-reference/",
|
||||
include_docs_urls(title="Labelbase API")
|
||||
),
|
||||
path(
|
||||
"account/apikey/",
|
||||
login_required(APIKeyView.as_view()),
|
||||
name="apikey"
|
||||
),
|
||||
path(
|
||||
"account/userprofile-avatar/",
|
||||
login_required(ProfileAvatarUpdateView.as_view()),
|
||||
name="userprofile_avatar",
|
||||
),
|
||||
path(
|
||||
"account/userprofile-currency/",
|
||||
login_required(ProfileCurrencyUpdateView.as_view()),
|
||||
name="userprofile_currency",
|
||||
),
|
||||
path(
|
||||
"account/userprofile/",
|
||||
login_required(ProfileView.as_view()),
|
||||
name="userprofile",
|
||||
),
|
||||
path(
|
||||
"labelbase/<pk>/delete/",
|
||||
login_required(LabelbaseDeleteView.as_view()),
|
||||
name="del_labelbase"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/",
|
||||
login_required(LabelbaseView.as_view()),
|
||||
name="labelbase"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/data/",
|
||||
login_required(LabelbaseDatatableView.as_view()),
|
||||
name="labelbase_label_data"),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/actions/<str:action>/",
|
||||
login_required(LabelbaseViewActionView.as_view()),
|
||||
name="labelbase_actions"),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/merge/",
|
||||
login_required(LabelbaseMergeView.as_view()),
|
||||
name="labelbase_merge"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/portfolio/",
|
||||
login_required(LabelbasePortfolioView.as_view()),
|
||||
name="labelbase_portfolio"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/edit/",
|
||||
login_required(LabelbaseUpdateView.as_view()),
|
||||
name="edit_labelbase"
|
||||
),
|
||||
path(
|
||||
"labelbase/import/",
|
||||
upload_labels,
|
||||
name="import_labels"
|
||||
),
|
||||
path(
|
||||
"labelbase/export/<int:labelbase_id>/",
|
||||
stream_labels_as_jsonl,
|
||||
name="export_labels"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/dyanmic-export/",
|
||||
login_required(ExportLabelsView.as_view()),
|
||||
name="labelbase_dynamic_export"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:labelbase_id>/fix-and-manage/",
|
||||
login_required(FixAndMergeLabelsView.as_view()),
|
||||
name="labelbase_fix_and_manage"
|
||||
),
|
||||
#path(
|
||||
# "labelbase/<int:labelbase_id>/stats-and-kpi/",
|
||||
# login_required(StatsAndKPIView.as_view()),
|
||||
# name="labelbase_stats_and_kpi"
|
||||
#),
|
||||
path(
|
||||
"labelbase/<int:pk>/tree-maps/",
|
||||
login_required(TreeMapsView.as_view()),
|
||||
name="labelbase_tree_maps"
|
||||
),
|
||||
path(
|
||||
"labelbase/<int:pk>/tree-maps/<str:action>/",
|
||||
login_required(TreeMapsView.as_view()),
|
||||
name="labelbase_tree_maps"
|
||||
),
|
||||
path(
|
||||
"labelbase/",
|
||||
login_required(LabelbaseFormView.as_view()),
|
||||
name="labelbase_new"
|
||||
),
|
||||
path(
|
||||
"label/<int:pk>/edit/",
|
||||
login_required(LabelUpdateView.as_view()),
|
||||
name="edit_label"
|
||||
),
|
||||
path(
|
||||
"label/<int:pk>/edit/<str:action>/",
|
||||
login_required(LabelUpdateView.as_view()),
|
||||
name="edit_label_with_action"
|
||||
),
|
||||
path(
|
||||
"label/<int:pk>/delete/",
|
||||
login_required(LabelDeleteView.as_view()),
|
||||
name="del_label"
|
||||
),
|
||||
path(
|
||||
"account/logout/",
|
||||
LogoutView.as_view(),
|
||||
name="logout"
|
||||
),
|
||||
path(
|
||||
"account/register/",
|
||||
RegistrationView.as_view(),
|
||||
name="registration"
|
||||
),
|
||||
path(
|
||||
"account/register/done/",
|
||||
RegistrationCompleteView.as_view(),
|
||||
name="registration_complete"
|
||||
),
|
||||
path(
|
||||
"account/change-password/",
|
||||
auth_views.PasswordChangeView.as_view(
|
||||
template_name="change_password.html",
|
||||
success_url="/"
|
||||
),
|
||||
name="change_password"
|
||||
),
|
||||
path(
|
||||
"privacy-policy",
|
||||
PrivacyView.as_view(),
|
||||
name="privacy_policy"
|
||||
),
|
||||
path(
|
||||
"terms",
|
||||
TermsView.as_view(),
|
||||
name="terms"
|
||||
),
|
||||
path(
|
||||
"faq",
|
||||
FaqView.as_view(),
|
||||
name="faq"
|
||||
),
|
||||
path(
|
||||
"about",
|
||||
AboutView.as_view(),
|
||||
name="about"
|
||||
),
|
||||
path(
|
||||
"encryption",
|
||||
EncryptionView.as_view(),
|
||||
name="encryption"
|
||||
),
|
||||
path(
|
||||
"interoperational",
|
||||
InteroperationalView.as_view(),
|
||||
name="interoperational"
|
||||
),
|
||||
path(
|
||||
"",
|
||||
HomeView.as_view(),
|
||||
name="home"
|
||||
),
|
||||
path(
|
||||
"",
|
||||
include(tf_urls)
|
||||
),
|
||||
path(
|
||||
"",
|
||||
include("user_sessions.urls", "user_sessions")
|
||||
),
|
||||
]
|
||||
|
||||
#urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
#if settings.DEBUG:
|
||||
urlpatterns.append(path("admin/", admin.site.urls))
|
||||
37
django/labellabor/utils.py
Normal file
37
django/labellabor/utils.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import re
|
||||
import decimal
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
def hashtag_to_badge(value):
|
||||
hashtags = re.findall(r'#\w+', value)
|
||||
for tag in hashtags:
|
||||
clean_tag = re.search(r'#(\w+)', tag).group(1) # Extract the word after the '#' symbol
|
||||
value = value.replace(tag, f'<a href="?tag={clean_tag}" class="badge badge-hashtag">{clean_tag}</a>')
|
||||
return value
|
||||
|
||||
|
||||
def extract_fiat_value(s):
|
||||
# CHF XXX
|
||||
pattern = r"({})\s?(\d+(?:\.\d+)?)"
|
||||
for currency in settings.CURRENCIES:
|
||||
match = re.search(pattern.format(currency), s)
|
||||
if match:
|
||||
print(f"Currency: {match.group(1)}, Value: {match.group(2)}")
|
||||
return (decimal.Decimal(match.group(2)), match.group(1))
|
||||
|
||||
# XXX CHF
|
||||
pattern = r"(\d+(?:\.\d+)?)\s?({})"
|
||||
for currency in settings.CURRENCIES:
|
||||
match = re.search(pattern.format(currency), s)
|
||||
if match:
|
||||
value = decimal.Decimal(match.group(1))
|
||||
currency_symbol = currency
|
||||
# Find the currency symbol position in the string
|
||||
symbol_start = match.start(2)
|
||||
symbol_end = match.end(2)
|
||||
if symbol_start > 0:
|
||||
currency_symbol = s[symbol_start:symbol_end]
|
||||
print(f"Currency: {currency_symbol}, Value: {value}")
|
||||
return (value, currency_symbol)
|
||||
return (decimal.Decimal(-1), "")
|
||||
650
django/labellabor/views.py
Normal file
650
django/labellabor/views.py
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
import os
|
||||
import time
|
||||
import tempfile
|
||||
import json
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.shortcuts import redirect, resolve_url
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.views.generic import FormView, TemplateView
|
||||
from django.views import View
|
||||
from django.shortcuts import render
|
||||
from django.views.generic.list import ListView
|
||||
from django.views.generic.edit import DeleteView
|
||||
from django.views.generic.edit import UpdateView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from two_factor.views import OTPRequiredMixin
|
||||
from two_factor.views.utils import class_view_decorator
|
||||
from labelbase.models import Label, Labelbase
|
||||
from labelbase.forms import LabelForm, LabelbaseForm
|
||||
from labelbase.forms import ExportLabelsForm
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import FileResponse
|
||||
from rest_framework.authtoken.models import Token
|
||||
from bip329.bip329_writer import BIP329JSONLWriter, BIP329JSONLEncryptedWriter
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.urls import reverse
|
||||
from django_datatables_view.base_datatable_view import BaseDatatableView
|
||||
from django.utils.html import escape
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from .utils import hashtag_to_badge, extract_fiat_value
|
||||
from labelbase.utils import compute_type_ref_hash
|
||||
from finances.models import OutputStat
|
||||
from finances.tasks import check_all_outputs
|
||||
|
||||
class AboutView(TemplateView):
|
||||
template_name = "about.html"
|
||||
|
||||
|
||||
class EncryptionView(TemplateView):
|
||||
template_name = "encryption.html"
|
||||
|
||||
|
||||
class InteroperationalView(TemplateView):
|
||||
template_name = "interoperational.html"
|
||||
|
||||
|
||||
class HomeView(TemplateView):
|
||||
template_name = "home.html"
|
||||
|
||||
|
||||
class PrivacyView(TemplateView):
|
||||
template_name = "privacy.html"
|
||||
|
||||
|
||||
class TermsView(TemplateView):
|
||||
template_name = "terms.html"
|
||||
|
||||
|
||||
class FaqView(TemplateView):
|
||||
template_name = "faq.html"
|
||||
|
||||
|
||||
class LabelDeleteView(DeleteView):
|
||||
model = Label
|
||||
success_url = "/"
|
||||
error_url = "/#failed"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if self.object.labelbase.user != self.request.user:
|
||||
return redirect(self.error_url)
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class LabelbaseDeleteView(DeleteView):
|
||||
model = Labelbase
|
||||
success_url = "/"
|
||||
error_url = "/#failed"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if self.object.user != self.request.user:
|
||||
return redirect(self.error_url)
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class LabelbaseDatatableView(BaseDatatableView):
|
||||
model = Label
|
||||
|
||||
columns = ["id", "type", "ref", "label", "origin", "spendable"]
|
||||
|
||||
order_columns = ["id", "type", "ref", "label", "origin", "spendable"]
|
||||
|
||||
max_display_length = 100
|
||||
|
||||
def get_initial_queryset(self):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
|
||||
search_tag = self.request.GET.get('tag', None)
|
||||
|
||||
qs = Label.objects.filter(labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=labelbase_id).order_by("id")
|
||||
|
||||
if search_tag:
|
||||
# Due to encryption, we need to use a super slow process here...
|
||||
res_ids = []
|
||||
search = f'#{search_tag}'
|
||||
print(search)
|
||||
for record in qs:
|
||||
if record.label and search in record.label:
|
||||
res_ids.append(record.id)
|
||||
continue
|
||||
qs = qs.filter(id__in=res_ids)
|
||||
return qs
|
||||
|
||||
|
||||
def render_column(self, row, column):
|
||||
if column == 'id':
|
||||
return f'<tt><a href="{reverse("edit_label", args=[row.id])}">{row.id}</a></tt>'
|
||||
elif column == 'type':
|
||||
return "<tt>{}</tt>".format(row.get_type_display())
|
||||
elif column == 'ref':
|
||||
return render_to_string('labelbase_dt_ref.html',
|
||||
context={'row': row,
|
||||
'mempool_url': row.get_mempool_url(),
|
||||
}, request=self.request)
|
||||
elif column == 'label':
|
||||
if row.label is None:
|
||||
return ""
|
||||
if row.labelbase.user.profile.use_hashtags:
|
||||
return hashtag_to_badge(f'<tt>{row.label}</tt>')
|
||||
else:
|
||||
return f'<tt>{row.label}</tt>'
|
||||
elif column == 'origin':
|
||||
if row.origin is None:
|
||||
return ""
|
||||
return f'<tt>{row.origin}</tt>'
|
||||
elif column == 'spendable':
|
||||
spendable_value = row.spendable
|
||||
if spendable_value is None:
|
||||
spendable_formatted = ''
|
||||
else:
|
||||
spendable_formatted = 'true' if spendable_value else 'false'
|
||||
#if spendable_formatted == 'true':
|
||||
# return f'<span class="badge badge-spendable fs--2 "><svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check ms-1" style="height:12.8px;width:12.8px;"><polyline points="20 6 9 17 4 12"></polyline></svg> <span class="badge-label"><tt>{spendable_formatted }</tt></span> </span>'
|
||||
#elif spendable_formatted == 'false':
|
||||
# return f'<span class="badge badge-unspendable fs--2 "><svg xmlns="http://www.w3.org/2000/svg" width="12.4" height="12.4" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6L6 18M6 6l12 12"/></svg><span class="badge-label"><tt>{spendable_formatted }</tt></span></span>'
|
||||
return f'<tt>{spendable_formatted }</tt>'
|
||||
else:
|
||||
return super(LabelbaseDatatableView, self).render_column(row, column)
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
search = self.request.GET.get('search[value]', None)
|
||||
if search:
|
||||
# Due to encryption, we need to use a super slow process here...
|
||||
res_ids = []
|
||||
search = search.lower()
|
||||
for record in qs:
|
||||
if record.type and search in record.type.lower():
|
||||
res_ids.append(record.id)
|
||||
continue
|
||||
if record.ref and search in record.ref.lower():
|
||||
res_ids.append(record.id)
|
||||
continue
|
||||
if record.label and search in record.label.lower():
|
||||
res_ids.append(record.id)
|
||||
continue
|
||||
if record.origin and search in record.origin.lower():
|
||||
res_ids.append(record.id)
|
||||
continue
|
||||
|
||||
return qs.filter(id__in=res_ids)
|
||||
return qs
|
||||
|
||||
class LabelbaseViewActionView(View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=self.kwargs["labelbase_id"], user_id=self.request.user.id
|
||||
)
|
||||
if self.kwargs["action"] == "update-spent-outputs":
|
||||
check_all_outputs(self.request.user.id, labelbase_id=labelbase.id)
|
||||
return HttpResponseRedirect(labelbase.get_absolute_url())
|
||||
|
||||
|
||||
|
||||
|
||||
class LabelbaseView(ListView):
|
||||
template_name = "labelbase.html"
|
||||
context_object_name = "label_list"
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Label.objects.filter(
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["labelbase_id"],
|
||||
)
|
||||
return qs.order_by("id")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
context = super(LabelbaseView, self).get_context_data(**kwargs)
|
||||
context["labelbase"] = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
context["active_labelbase_id"] = labelbase_id
|
||||
context["labelform"] = LabelForm(
|
||||
request=self.request, labelbase_id=labelbase_id
|
||||
)
|
||||
context["api_token"] = Token.objects.get(user_id=self.request.user.id)
|
||||
return context
|
||||
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
labelform = LabelForm(request.POST, request=request, labelbase_id=labelbase_id)
|
||||
if labelform.is_valid():
|
||||
label = labelform.save()
|
||||
return HttpResponseRedirect(label.labelbase.get_absolute_url())
|
||||
|
||||
|
||||
class LabelbaseMergeView(LabelbaseView):
|
||||
template_name = "labelbase_merge.html"
|
||||
|
||||
def get_queryset(self):
|
||||
labels = []
|
||||
qs = Label.objects.filter(
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["labelbase_id"],
|
||||
)
|
||||
lbl_type = self.request.GET.get("type", None)
|
||||
lbl_ref = self.request.GET.get("ref", None)
|
||||
lbl_label = self.request.GET.get("label", None)
|
||||
|
||||
for l in qs:
|
||||
if lbl_type and lbl_ref and lbl_label:
|
||||
if l.type == lbl_type and l.ref == lbl_ref and l.label == lbl_label:
|
||||
labels.append(l)
|
||||
elif lbl_type and lbl_ref:
|
||||
if l.type == lbl_type and l.ref == lbl_ref:
|
||||
labels.append(l)
|
||||
elif lbl_type and lbl_label:
|
||||
if l.type == lbl_type and l.label == lbl_label:
|
||||
labels.append(l)
|
||||
elif lbl_ref and lbl_label:
|
||||
if l.ref == lbl_ref and l.label == lbl_label:
|
||||
labels.append(l)
|
||||
elif lbl_type:
|
||||
if l.type == lbl_type:
|
||||
labels.append(l)
|
||||
elif lbl_ref:
|
||||
if l.ref == lbl_ref:
|
||||
labels.append(l)
|
||||
elif lbl_label or lbl_label == '':
|
||||
if l.label == lbl_label:
|
||||
labels.append(l)
|
||||
label_ids = []
|
||||
for l in labels:
|
||||
label_ids.append(l.id)
|
||||
if label_ids:
|
||||
qs = Label.objects.filter(id__in=label_ids,
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["labelbase_id"])
|
||||
else:
|
||||
qs = Label.objects.none()
|
||||
return qs.order_by("id")
|
||||
|
||||
class StatsAndKPIView(View):
|
||||
template_name = "labelbase_stats_and_kpi.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
return render(request, self.template_name, {
|
||||
"labelbase": labelbase,
|
||||
"active_labelbase_id": labelbase_id})
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["active_labelbase_id"] = self.object.labelbase.id
|
||||
context["labelbase"] = self.object.labelbase
|
||||
context["action"] = self.kwargs.get('action', 'unspent-outputs')
|
||||
if context["action"] == "labeling":
|
||||
#mempool_api = self.object.labelbase.get_mempool_api()
|
||||
if self.object.type == "tx":
|
||||
mempool_api = self.object.labelbase.get_mempool_api()
|
||||
context["res_tx"] = mempool_api.get_transaction(self.object.ref)
|
||||
|
||||
if self.object.type == "output":
|
||||
context["output"] = OutputStat.objects.filter(type_ref_hash= \
|
||||
self.object.type_ref_hash).last()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
class TreeMapsView(ListView):
|
||||
context_object_name = "label_list"
|
||||
|
||||
def get_template_names(self):
|
||||
if 'action' in self.kwargs:
|
||||
action = self.kwargs['action']
|
||||
if action == 'unspent-outputs':
|
||||
return "labelbase_tree_maps_unspent_outputs.html"
|
||||
elif action == 'unspent-spendable-outputs':
|
||||
return "labelbase_tree_maps_unspent_outputs.html"
|
||||
return "labelbase_tree_maps_unspent_outputs.html"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
labelbase_id = self.kwargs["pk"]
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
context['labelbase'] = labelbase
|
||||
context['active_labelbase_id'] = labelbase.id
|
||||
context['action'] = self.kwargs.get('action', 'unspent-outputs')
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
#action = self.kwargs.get('action', 'unspent-outputs')
|
||||
|
||||
label_ids = []
|
||||
|
||||
qs = Label.objects.filter(
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["pk"],
|
||||
)
|
||||
|
||||
for l in qs:
|
||||
if l.type == "output":
|
||||
output = OutputStat.objects.filter(
|
||||
type_ref_hash=l.type_ref_hash,
|
||||
network=l.labelbase.network).last()
|
||||
if output and output.spent is False:
|
||||
#if action == 'unspent-spendable-outputs' and l.spendable == True:
|
||||
# label_ids.append(l.id)
|
||||
#else:
|
||||
label_ids.append(l.id)
|
||||
if label_ids:
|
||||
qs = qs.filter(id__in=label_ids,
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["pk"])
|
||||
else:
|
||||
qs = Label.objects.none()
|
||||
return qs.order_by("id")
|
||||
|
||||
|
||||
|
||||
class LabelbasePortfolioView(LabelbaseView):
|
||||
template_name = "labelbase_portfolio.html"
|
||||
|
||||
def get_queryset(self):
|
||||
self.balances = {}
|
||||
label_ids = []
|
||||
qs = Label.objects.filter(
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["labelbase_id"],
|
||||
)
|
||||
for l in qs:
|
||||
if l.type == "output":
|
||||
val, cur = extract_fiat_value(l.label)
|
||||
if val > 0:
|
||||
if self.balances.get(cur, None) is None:
|
||||
self.balances[cur] = 0
|
||||
self.balances[cur] += val
|
||||
label_ids.append(l.id)
|
||||
if label_ids:
|
||||
qs = Label.objects.filter(id__in=label_ids,
|
||||
labelbase__user_id=self.request.user.id,
|
||||
labelbase_id=self.kwargs["labelbase_id"])
|
||||
else:
|
||||
qs = Label.objects.none()
|
||||
return qs.order_by("id")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['balances'] = self.balances
|
||||
return context
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FixAndMergeLabelsView(View):
|
||||
template_name = "label_fix_and_merge.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
|
||||
# Fetch all records for the specified Labelbase
|
||||
records = Label.objects.filter(labelbase_id=labelbase_id)
|
||||
|
||||
# Create a dictionary to store records grouped by type, ref, and label
|
||||
record_groups_type_and_ref = {}
|
||||
record_groups_type_and_ref_and_label = {}
|
||||
record_groups_all_identical = {}
|
||||
|
||||
resulting_duplicates_type_and_ref = []
|
||||
resulting_duplicates_type_and_ref_and_label = []
|
||||
resulting_duplicates_all_identical = []
|
||||
all_identical_records = []
|
||||
|
||||
# Iterate through the records and group them
|
||||
for record in records:
|
||||
key_type_and_ref = (record.type, record.ref)
|
||||
key_type_and_ref_label = (record.type, record.ref, record.label)
|
||||
key_all_identical = (record.type, record.ref, record.label, record.origin, record.spendable)
|
||||
|
||||
if key_type_and_ref in record_groups_type_and_ref:
|
||||
record_groups_type_and_ref[key_type_and_ref].append(record)
|
||||
else:
|
||||
record_groups_type_and_ref[key_type_and_ref] = [record]
|
||||
|
||||
if key_type_and_ref_label in record_groups_type_and_ref_and_label:
|
||||
record_groups_type_and_ref_and_label[key_type_and_ref_label].append(record)
|
||||
else:
|
||||
record_groups_type_and_ref_and_label[key_type_and_ref_label] = [record]
|
||||
|
||||
if key_all_identical in record_groups_all_identical:
|
||||
record_groups_all_identical[key_all_identical].append(record)
|
||||
else:
|
||||
record_groups_all_identical[key_all_identical] = [record]
|
||||
|
||||
# Iterate through the grouped records and identify duplicates
|
||||
for key_type_and_ref, duplicates in record_groups_type_and_ref.items():
|
||||
if len(duplicates) > 1:
|
||||
type_val, ref_val = key_type_and_ref
|
||||
print(f"Duplicates for labelbase_id={labelbase_id}, type='{type_val}', ref='{ref_val}', ")
|
||||
for record in duplicates:
|
||||
print(f" ID: {record.id}, origin: {record.origin}, spendable: {record.spendable}")
|
||||
resulting_duplicates_type_and_ref.append({'type': type_val, 'ref': ref_val})
|
||||
|
||||
for key_type_and_ref_and_label, duplicates in record_groups_type_and_ref_and_label.items():
|
||||
if len(duplicates) > 1:
|
||||
type_val, ref_val, label_val = key_type_and_ref_and_label
|
||||
print(f"Duplicates for labelbase_id={labelbase_id}, type='{type_val}', ref='{ref_val}', label='{label_val}':")
|
||||
for record in duplicates:
|
||||
print(f" ID: {record.id}, origin: {record.origin}, spendable: {record.spendable}")
|
||||
resulting_duplicates_type_and_ref_and_label.append({'type': type_val, 'ref': ref_val, 'label': label_val})
|
||||
|
||||
for key_all_identical, duplicates in record_groups_all_identical.items():
|
||||
if len(duplicates) > 1:
|
||||
type_val, ref_val, label_val, origin_val, spendable_cal = key_all_identical
|
||||
#print(f"Duplicates for labelbase_id={labelbase_id}, type='{type_val}', ref='{ref_val}', label='{label_val}':")
|
||||
for record in duplicates:
|
||||
if record not in all_identical_records:
|
||||
all_identical_records.append(record)
|
||||
# print(f" ID: {record.id}, origin: {record.origin}, spendable: {record.spendable}")
|
||||
resulting_duplicates_all_identical.append({'type': type_val, 'ref': ref_val, 'label': label_val,
|
||||
'origin': origin_val, 'spendable': spendable_cal}) # nonsense, but counts
|
||||
|
||||
|
||||
|
||||
fix_suggestions = len(resulting_duplicates_type_and_ref) + \
|
||||
len(resulting_duplicates_type_and_ref_and_label) + \
|
||||
len(resulting_duplicates_all_identical)
|
||||
|
||||
return render(request, self.template_name, {
|
||||
"labelbase": labelbase,
|
||||
"fix_suggestions": fix_suggestions,
|
||||
"resulting_duplicates_all_identical_final_record_count": len(resulting_duplicates_all_identical),
|
||||
"resulting_duplicates_all_identical_current_record_count": len(all_identical_records),
|
||||
|
||||
"resulting_duplicates_type_and_ref": resulting_duplicates_type_and_ref,
|
||||
"resulting_duplicates_type_and_ref_and_label": resulting_duplicates_type_and_ref_and_label,
|
||||
"active_labelbase_id": labelbase_id})
|
||||
|
||||
|
||||
class ExportLabelsView(View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
form = ExportLabelsForm(request.POST)
|
||||
if form.is_valid():
|
||||
# Retrieve data from the form
|
||||
tx_checkbox = form.cleaned_data['tx_checkbox']
|
||||
addr_checkbox = form.cleaned_data['addr_checkbox']
|
||||
pubkey_checkbox = form.cleaned_data['pubkey_checkbox']
|
||||
input_checkbox = form.cleaned_data['input_checkbox']
|
||||
output_checkbox = form.cleaned_data['output_checkbox']
|
||||
xpub_checkbox = form.cleaned_data['xpub_checkbox']
|
||||
|
||||
encrypt_checkbox = form.cleaned_data['encrypt_checkbox']
|
||||
|
||||
# Use request.POST, not form.cleaned_data['passphrase']
|
||||
passphrase = request.POST.get('passphrase', '')
|
||||
|
||||
# Export labels based on selected checkboxes
|
||||
selected_type_attributes = []
|
||||
if tx_checkbox:
|
||||
selected_type_attributes.append('tx')
|
||||
if addr_checkbox:
|
||||
selected_type_attributes.append('addr')
|
||||
if pubkey_checkbox:
|
||||
selected_type_attributes.append('pubkey')
|
||||
if input_checkbox:
|
||||
selected_type_attributes.append('input')
|
||||
if output_checkbox:
|
||||
selected_type_attributes.append('output')
|
||||
if xpub_checkbox:
|
||||
selected_type_attributes.append('xpub')
|
||||
|
||||
timestamp = time.strftime('%Y%m%d%H%M%S')
|
||||
|
||||
# Define the prefix and file extension for the temporary file
|
||||
prefix = f'labelbase-{labelbase.id}-{timestamp}-'
|
||||
suffix = '.jsonl'
|
||||
|
||||
# Create a temporary file with the specified prefix and file extension
|
||||
with tempfile.NamedTemporaryFile(delete=False, prefix=prefix, suffix=suffix) as temp_file:
|
||||
# Create a BIP329JSONLWriter instance
|
||||
if encrypt_checkbox and passphrase:
|
||||
label_writer = BIP329JSONLEncryptedWriter(temp_file.name, passphrase, remove_existing=True)
|
||||
else:
|
||||
label_writer = BIP329JSONLWriter(temp_file.name, remove_existing=True)
|
||||
labels = Label.objects.filter(labelbase_id=labelbase_id,
|
||||
labelbase__user_id=request.user.id,
|
||||
type__in=selected_type_attributes
|
||||
).order_by("id")
|
||||
for label in labels:
|
||||
label_entry = {
|
||||
"type": label.type,
|
||||
"ref": label.ref,
|
||||
"label": label.label,
|
||||
}
|
||||
|
||||
if label.origin and label.type == "tx":
|
||||
label_entry["origin"] = label.origin
|
||||
if label.spendable in [True, False] and label.type == "output":
|
||||
label_entry["spendable"] = label.spendable
|
||||
|
||||
# Write the label entry to the file
|
||||
label_writer.write_label(label_entry)
|
||||
|
||||
final_filename = f"labelbase-{labelbase.id}-{timestamp}.jsonl"
|
||||
if encrypt_checkbox and passphrase:
|
||||
if label_writer.is_closed is False:
|
||||
# Close the encrypted writer when finished
|
||||
label_writer.close()
|
||||
final_filename = final_filename.replace(".jsonl", ".7z")
|
||||
|
||||
response = FileResponse(open(temp_file.name, 'rb'))
|
||||
response['Content-Type'] = 'application/json'
|
||||
|
||||
response['Content-Disposition'] = f'attachment; filename="{final_filename}"'
|
||||
os.remove(temp_file.name)
|
||||
return response
|
||||
# TODO: error message
|
||||
return HttpResponseRedirect(labelbase.get_absolute_url())
|
||||
|
||||
|
||||
class LabelUpdateView(UpdateView):
|
||||
model = Label
|
||||
fields = ["type", "ref", "label", "origin", "spendable"]
|
||||
|
||||
def get_template_names(self):
|
||||
if 'action' in self.kwargs:
|
||||
action = self.kwargs['action']
|
||||
if action == 'labeling':
|
||||
return "label_edit_labeling.html"
|
||||
return "label_edit_update.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["active_labelbase_id"] = self.object.labelbase.id
|
||||
context["labelbase"] = self.object.labelbase
|
||||
context["action"] = self.kwargs.get('action', 'update')
|
||||
if context["action"] == "labeling":
|
||||
#mempool_api = self.object.labelbase.get_mempool_api()
|
||||
if self.object.type == "tx":
|
||||
mempool_api = self.object.labelbase.get_mempool_api()
|
||||
context["res_tx"] = mempool_api.get_transaction(self.object.ref)
|
||||
|
||||
if self.object.type == "output":
|
||||
context["output"] = OutputStat.objects.filter(type_ref_hash= \
|
||||
self.object.type_ref_hash).last()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class LabelbaseUpdateView(UpdateView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
labelbase_id = self.kwargs["labelbase_id"]
|
||||
labelbase = get_object_or_404(
|
||||
Labelbase, id=labelbase_id, user_id=self.request.user.id
|
||||
)
|
||||
labelbase.name = request.POST.get("name", "")
|
||||
labelbase.fingerprint = request.POST.get("fingerprint", "")
|
||||
labelbase.about = request.POST.get("about", "")
|
||||
labelbase.operation_mode = request.POST.get("operation_mode", "")
|
||||
labelbase.network = request.POST.get("network", "")
|
||||
|
||||
labelbase.save()
|
||||
return HttpResponseRedirect(labelbase.get_absolute_url())
|
||||
|
||||
|
||||
class LabelbaseFormView(FormView):
|
||||
template_name = "labelbase_new.html"
|
||||
form_class = LabelbaseForm
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return redirect(resolve_url("home"))
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.request.user
|
||||
form.save()
|
||||
return redirect(form.instance.get_absolute_url())
|
||||
|
||||
|
||||
class RegistrationView(FormView):
|
||||
template_name = "registration.html"
|
||||
form_class = UserCreationForm
|
||||
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
return redirect("registration_complete")
|
||||
|
||||
|
||||
class RegistrationCompleteView(TemplateView):
|
||||
template_name = "registration_complete.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["login_url"] = resolve_url(settings.LOGIN_URL)
|
||||
return context
|
||||
|
||||
|
||||
@class_view_decorator(never_cache)
|
||||
class ExampleSecretView(OTPRequiredMixin, TemplateView):
|
||||
template_name = "secret.html"
|
||||
16
django/labellabor/wsgi.py
Normal file
16
django/labellabor/wsgi.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for labellabor project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "labellabor.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
Loading…
Add table
Add a link
Reference in a new issue