From cfc1f5d70a855b464fa02cae21a9b69cbd792b61 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 16 Feb 2026 00:51:24 +0000 Subject: [PATCH] ### Sua chave de administrador exclusiva: Guarde --- core/__pycache__/models.cpython-311.pyc | Bin 4694 -> 6064 bytes core/__pycache__/urls.cpython-311.pyc | Bin 453 -> 747 bytes core/__pycache__/views.cpython-311.pyc | Bin 2118 -> 5566 bytes ...onfig_cgiasset_assigned_artist_and_more.py | 36 +++ ...t_assigned_artist_and_more.cpython-311.pyc | Bin 0 -> 1670 bytes core/models.py | 19 +- core/templates/base.html | 57 +++- core/templates/core/admin_login.html | 39 +++ core/templates/core/asset_library.html | 89 +++++++ core/templates/core/index.html | 244 ++++++------------ core/urls.py | 7 +- core/views.py | 63 ++++- 12 files changed, 370 insertions(+), 184 deletions(-) create mode 100644 core/migrations/0003_studioconfig_cgiasset_assigned_artist_and_more.py create mode 100644 core/migrations/__pycache__/0003_studioconfig_cgiasset_assigned_artist_and_more.cpython-311.pyc create mode 100644 core/templates/core/admin_login.html create mode 100644 core/templates/core/asset_library.html diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 69a6b19e3f86b571c6ac2a6efb842dd5cf75e4b9..3fec2a3fa8f03da87ac79f3dc592fc6ddace79e0 100644 GIT binary patch delta 2453 zcmZ`)&2Jk;6yLSi-;O^L*9lbv+s18bKGKvXEud00aXwl~(+|5Kg3z*f#?Gc|Z<*1MWj+Ck}jw>Bn}ipgA~+D52zQo(SsvdRkRX+KoJtH=mAv-@!qUMtI&?MKhL~* zGxO&C-g|Q=v$ikxO9P1KqE%$b(i9o!%G%0z6ae+t|1>&RPv~T&# z&gIYiAwP@*?zk()HG&`swKU>EE((Jv(h>zi#G4ng(d8ev@0cj!ahpwQb^feE=TrOJ zK=%Ui5bvsV%_9ic;d9%h-y=|IINu$vq*JaQNY+PkaA;>a$^}@k^?eg&I5pdHh&v0OJ^F=nT^igrP*d@@7jTzR-q15Int0)8}VI>v(5OfZwDLk{p<1l&G`QMG5dI+`}sZKTi?@xUzwj;TuyHL;rEB) zVTLY&0AnHecYGh{YW4hG8Tk!I_tEMr4C_zjwDdXusvX^#*H0 znGfPYuaz05oa3`JOQ)IHb5)+`DU+HWv_N(^I+ z@i995#@B(19zQyq9kTa@d)m1-UxD!$L!%4qHMpiZzIxRh_n1712w zEtO%hI|iSL`LG#5aQ{@-(!s?b{@f)cI~bW8MqfIKGPT^GCz?5f z%$2nv)2_#I3-7@m>;S?5!a)QTpuh=d_}VzZllVjczmSDII4~^kVyJ5m0Oy}Oty)vE z!Q^vi-^7Om9}1$CHA~gylBUyElCnWq!7!RO_ZbxIhcT_M0wO1kltV!RwB}~0@>JsO z<@h%7J^Pz@f59a=wUy+^P(D9ePEUL2 zxPI!MbS0U#6Ujh?CmNoS4ck4*y(26EeaFYya_cw0GKL*DWlM}c3?7Epq^8p&>=LLT zpXNXIC&?ENZ3vM%|J{=!B2?@D!_vXe58p@mgGZCw?HkGWa|!XNcu#mTF3w)QaG%dT Kc!~zE1pfjr|5(NV delta 1233 zcmZ`&T}TvB6rQ^~vw!WMx~^tvshLfh8B~;%xUD~6Y1S@OLXGRrZ5JrIJhAOzo|x9F+Bkeat1?Mb00pStI+LWM2tcklhqxo5uf&6$;x>qnxmBax8A zf3Niy#@kRiT2G#r+Z&@EX-Lw&3z9BVGA);%)WsA*DV*}{Qa(ZXITff-^*%kAkq6+p&Yieoq?FKU-&Deyq<0ae+S zXS}AFN9V(1U`^A!(}jEk`y3czE8YX_RIv71W2N{ZzAO`H;fqZ;9EPJDUB9N;4rtnZ zY`4M=f%!HHdm?>{)hy0`3G9b}P@_=1Oy@+8u0Ng1q*MI^Fpd(s+3C1C?1nE{mPvC(;h-BfY%Ooi%$n4p zI-JA29)z0+=qcPl5Ix|lgp0e-!d}MLLn442POA5-B(cM!k*!v}3+s^uX*{M!`6$QO z_v+!ZBX~28P=!#7aE(J2u5;YbIknaAC&M rOD64wIer(vF#8jGlkD_t$}Cbhk&Y02=HB@9!Q!JW5&QL@458{b+IS|t diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index f74125d424b7afe8d71771b2bd5050ba3fe5022b..2b5aa39c72e9bf748e2ac011a4dd0c815fccb6b7 100644 GIT binary patch delta 492 zcmX@g{F+sLIWI340}y1UPs&`&$iVOz#DM`$DC6^%iR$t^xvWvFxolBvx$IHw6Wz?} znHW+TQ#eyuQ@GZ!En{Y2SPjGw0G8oSWlQ0~D#M$~p2CMNlg=8&k-{I$pegVYWQZo? zEtZ1Bl8l!?H!*0k-eSqf&rQ9>S5TCnm6}`0zqDlH1}(QLcChMV{UUatp;f}gC8a5u`MO|b`d~f!MI0a* z5p)@#0s2Lt(D2jboOoB62W$XXZ4u|hzX5(iKq-(zi?;!Z56p~=j5io$E})_t41pJj zLz6ohb^LCya5T7dNKWuw!GD3p;v$R16&4Gy*ac3x1>75SFR(aVWO2B{;s6ztUm&x= b?*fbSMHc5PEY2Ue+4z|nxIwT;0O%$Frxb`5 delta 178 zcmaFOdX!mxIWI340}#X{P0Bn7q#uJgFu(?7e2$u^E z@fJ%#VoAnJMi7VT7E4BcZt5+*f};Ga)Z~)*l+=>M%$&(4j9SconrxGoFe*>J#^}q% n4^#}&P@Fbdmq|uU{Q?6PG`WyTN8kf1Ge1)UHwYH-0(AfYTcRrC diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 500c278f719eadeb85cb303c29ee0e52def9f9c3..7b260f032559655f2b629462ae65ec551fb7a401 100644 GIT binary patch literal 5566 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 JCri3<{{^=U^HBf* delta 963 zcmZ`%&ubGw6rRoQ&Tg7ylcqnVHcf18T+~{%#EVG9gBK}6(ZU{#X?9Fgce8bNqot%Y z2mb)uxvKP_RjC*8E_zXqsR#{w5HEtg1;mRY`ethi1$|7ueD9k#Gw++(S4ZC_v?sAx z2ZETHT`PZ*R<(ZN+G;knA_>SurfA7FHn6Q2N{~yIYKM(5aM{FGhaE8@cGQU4F(U?= zau*qzsRG7LVH)Y-9lr6DF8GlW@$$C`b<0jg5BZpqib<&7$z^ADo)qDa<|oD{pjP$D zHi;}b6|y71a$RIOA=6*vyd4;b2)}Q2fxVMXv8HxuEvezJnZ0&>dFrAZE50KQUmDjr$%T)r$F1e+1Zd!#wXCNu>ie@*u}KpnAdH6yn$>P@kq zYH_#~!ExL|0QHOCH55(W%Qgm%JuPiTavvkPhLrn;UgkS52%}M0?c;*$63>MfkzA`< z(nVicpbmd4%I9f@y-B85WKOv$+QXrjLonUPS%yPkOQHjuAL1~~;UIv^r?>|?2*lU^ z?w>b_S14O_1jL}s0a8a_w4uk!qxg1u@I6VTj^TUo4 diff --git a/core/migrations/0003_studioconfig_cgiasset_assigned_artist_and_more.py b/core/migrations/0003_studioconfig_cgiasset_assigned_artist_and_more.py new file mode 100644 index 0000000..295d47f --- /dev/null +++ b/core/migrations/0003_studioconfig_cgiasset_assigned_artist_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 5.2.7 on 2026-02-16 00:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_alter_pipelinestep_name'), + ] + + operations = [ + migrations.CreateModel( + name='StudioConfig', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('admin_access_key', models.CharField(max_length=100, unique=True)), + ('is_setup', models.BooleanField(default=False)), + ], + ), + migrations.AddField( + model_name='cgiasset', + name='assigned_artist', + field=models.CharField(blank=True, max_length=100), + ), + migrations.AddField( + model_name='cgiasset', + name='file_location', + field=models.CharField(blank=True, help_text='Path or URL to the digital file', max_length=500), + ), + migrations.AddField( + model_name='cgiasset', + name='version', + field=models.PositiveIntegerField(default=1), + ), + ] diff --git a/core/migrations/__pycache__/0003_studioconfig_cgiasset_assigned_artist_and_more.cpython-311.pyc b/core/migrations/__pycache__/0003_studioconfig_cgiasset_assigned_artist_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f36064cbbfbd5b1a0306b46007c685ddf98b9d03 GIT binary patch literal 1670 zcmah|J!~5{6y}{yKPStHbg`o}iDT7?+bXCnwS@r}2<#>XYsAIc4)pjtk+All3Gv44zMPA5~sT9J#mzMF@~+7;!K3h#4A|GS~t6=3X~Y9sF4Vz$16D5&FzUi z_Qi-XW}-WK)-K8_Dx$>TOZf7+SQ^&5`Lj0N!r3xi@L^o=aRrZc$In{*ua~Qlm$;?? z7tf#Pya!XOMS{SgPL5W`1wPwKKi<>@f`9!2i6%u9>IL1!)P0^E!ZMkTz3hh$fDcAeuJ>&IMFPGE1$hp_mp-!ON#qQZ4zV$@>y)@mzA`?t6xH>K%$P~a^V|b! z-WL^rD9_FHr6yuSHTS@AEQ0LeEOQ^@p*Hr+aj8c)$Rpb$COJW8oenv9s=tFH;TXJa zRGLnkRQxsH_WTOjBy|ynRlavv%k7{#sYses-aYY(Aj}ugjd)Rycmd-}famT2A{&cS zGcw!RVkr?U5>j#JM1^)v`yd7M&jtx~EVc7^kOlhWkJ&JDt6!M>t1uoE@9u7d#k&XE z>pMXW1~v literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index 9b7a9e0..de6be32 100644 --- a/core/models.py +++ b/core/models.py @@ -1,5 +1,19 @@ from django.db import models from django.utils.text import slugify +import uuid + +class StudioConfig(models.Model): + """Singleton model to store studio-wide settings and the unique admin key.""" + admin_access_key = models.CharField(max_length=100, unique=True) + is_setup = models.BooleanField(default=False) + + def save(self, *args, **kwargs): + if not self.admin_access_key: + self.admin_access_key = str(uuid.uuid4()) + super().save(*args, **kwargs) + + def __str__(self): + return "Studio Configuration" class Project(models.Model): TYPES = ( @@ -72,6 +86,9 @@ class CgiAsset(models.Model): asset_type = models.CharField(max_length=10, choices=ASSET_TYPES) is_realistic = models.BooleanField(default=True) current_stage = models.CharField(max_length=100, default='Modeling') + version = models.PositiveIntegerField(default=1) + file_location = models.CharField(max_length=500, blank=True, help_text="Path or URL to the digital file") + assigned_artist = models.CharField(max_length=100, blank=True) def __str__(self): - return f"{self.name} ({self.get_asset_type_display()})" \ No newline at end of file + return f"{self.name} ({self.get_asset_type_display()})" diff --git a/core/templates/base.html b/core/templates/base.html index a656bcd..b40e57e 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,3 +1,4 @@ +{% load static %} @@ -7,15 +8,17 @@ - + + + {% block extra_head %}{% endblock %} @@ -38,7 +55,7 @@
+ {% if messages %} +
+ {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} {% block content %}{% endblock %}
-

© 2026 CGI Virtual Studio. Powered by AI Pipeline.

+

© 2026 CGI Virtual Studio. Secure Command Center.

@@ -71,4 +100,4 @@ {% block extra_js %}{% endblock %} - + \ No newline at end of file diff --git a/core/templates/core/admin_login.html b/core/templates/core/admin_login.html new file mode 100644 index 0000000..7bfa4fc --- /dev/null +++ b/core/templates/core/admin_login.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block content %} +
+
+
+ +

Acesso Restrito

+

Insira sua Chave Privada de Administrador para prosseguir.

+
+ +
+ {% csrf_token %} +
+ +
+ +
+ + +
+
+ + +{% endblock %} diff --git a/core/templates/core/asset_library.html b/core/templates/core/asset_library.html new file mode 100644 index 0000000..40b6400 --- /dev/null +++ b/core/templates/core/asset_library.html @@ -0,0 +1,89 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

Biblioteca de Assets

+

Catálogo central de personagens, cenários e objetos digitais.

+
+
+ Total de Assets + {{ assets|length }} +
+
+ + + + +
+ +
+
+ {% for asset in assets %} +
+
+
+
+ {{ asset.get_asset_type_display }} + v{{ asset.version }} +
+
{{ asset.name }}
+

Projeto: {{ asset.project.title }}

+ +
+ {{ asset.current_stage }} +
+
+
+
+ {% empty %} +
+

Nenhum asset cadastrado ainda.

+
+ {% endfor %} +
+
+ + +
+
+ {% for asset in asset_types.CHAR %} +
+ +
+
+
{{ asset.name }}
+

{{ asset.project.title }}

+
+
+
+ {% endfor %} +
+
+ +
+
+ + +{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index d224271..07aa9a3 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,181 +1,101 @@ {% extends "base.html" %} -{% load static %} - -{% block title %}Command Center | Studio CGI Virtual{% endblock %} {% block content %} -
-
-
- NEXT-GEN CGI PIPELINE +
+ +
+
+

STUDIO COMMAND CENTER

+

Gerenciamento de Super-Produções CGI

-

Studio de Cinema Virtual

-

- A fábrica digital para super-produções. Gerencie do roteiro à renderização em um fluxo de produção rigoroso e colaborativo. -

-
- Acessar Produções - Nova Super-Produção + +
+
+ Projetos Ativos + {{ active_productions }} +
+
+ Status do Sistema + ONLINE +
-
-
-
-
-
-
- Total de Projetos - {{ total_projects }} + +
+
+
+ +
+ {% if is_admin %} + MODO ADMIN + Sair + {% else %} + + Acesso Restrito + + {% endif %}
-
-
- Produções Ativas - {{ active_productions }} -
-
-
-
- Obras Finalizadas - {{ completed_projects }} -
-
-
- -
-
-

Produções em Andamento

-

Status em tempo real do pipeline CGI

-
-
- -
- {% for project in projects %} -
-
-
- {{ project.get_status_display }} - {{ project.get_project_type_display }} -
- -

- - {{ project.title }} - -

- -

- {{ project.description|default:"Sem descrição definida para esta super-produção."|truncatewords:20 }} -

- -
-
- Progresso do Pipeline - {% with last_step=project.steps.last %} - {{ last_step.progress|default:0 }}% - {% endwith %} -
-
- {% with last_step=project.steps.last %} -
- {% endwith %} -
- -
- {% for step in project.steps.all|slice:":4" %} - - {{ step.get_name_display }} - - {% endfor %} - {% if project.steps.count > 4 %} - +{{ project.steps.count|add:"-4" }} - {% endif %} -
-
- - -
-
- {% empty %} -
-
- - - - -
-

Nenhuma produção ativa

-

Comece sua primeira super-produção 3D agora.

- Iniciar Projeto -
- {% endfor %}
-
-
-
-
-
-

Pipeline CGI Profissional

-

Nosso estúdio segue o fluxo de trabalho dos maiores estúdios de Hollywood, garantindo qualidade em cada quadro.

-
-
-
-

Pré-produção

-

Roteiro, Concept Art e Animatic para definir a alma do filme.

-
-
-
-
-

Produção

-

Modelagem, Rigging e Animação com personagens realistas.

-
-
-
-
-

Iluminação & FX

-

Simulação de partículas, fluidos e luzes cinematográficas.

-
-
-
-
-

Pós-produção

-

Renderização em render farm e composição final.

-
-
-
-
-
-
-
-
-
-
-
+ +
+ {% for project in projects %} +
+
+
+
+ {% if project.thumbnail_url %} + {{ project.title }} + {% else %} +
+
-

Status da Render Farm

-
-
- Nodes Ativos - 128 / 128 -
-
- CPU Load - 94% -
-
- Tempo Estimado - 04:12:33 -
-
-
+ {% endif %} +
+
+
+
+

{{ project.title }}

+ + {{ project.get_status_display }} + +
+

{{ project.description|truncatewords:20 }}

+ + +
+
+ Progresso Geral + 85% +
+
+
+
+
+ + + Ver Pipeline Detalhado +
+ {% endfor %}
-
-{% endblock %} \ No newline at end of file + + + +{% endblock %} diff --git a/core/urls.py b/core/urls.py index b9e0a07..dc67e2f 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,10 @@ from django.urls import path -from .views import home, project_detail +from .views import home, project_detail, asset_library, admin_login, admin_logout urlpatterns = [ path("", home, name="home"), path("project//", project_detail, name="project_detail"), -] \ No newline at end of file + path("assets/", asset_library, name="asset_library"), + path("studio-admin/login/", admin_login, name="admin_login"), + path("studio-admin/logout/", admin_logout, name="admin_logout"), +] diff --git a/core/views.py b/core/views.py index 9e5fe2c..e0f522a 100644 --- a/core/views.py +++ b/core/views.py @@ -1,17 +1,31 @@ import os import platform - +from functools import wraps from django import get_version as django_version -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import render, get_object_or_404, redirect from django.utils import timezone -from .models import Project, PipelineStep, CgiAsset +from django.contrib import messages +from .models import Project, PipelineStep, CgiAsset, StudioConfig +def studio_admin_required(view_func): + """Decorator to restrict access to studio admin only.""" + @wraps(view_func) + def _wrapped_view(request, *args, **kwargs): + if not request.session.get('is_studio_admin', False): + messages.warning(request, "Acesso restrito. Por favor, insira sua chave de administrador.") + return redirect('admin_login') + return view_func(request, *args, **kwargs) + return _wrapped_view def home(request): """Render the CGI Studio Command Center.""" + # Ensure StudioConfig exists and generate key if needed + config, created = StudioConfig.objects.get_or_create(id=1) + if created or not config.admin_access_key: + config.save() # Triggers uuid generation + projects = Project.objects.prefetch_related('steps').all() - # Simple statistics for the dashboard total_projects = projects.count() active_productions = projects.filter(status='PROD').count() completed_projects = projects.filter(status='DONE').count() @@ -22,9 +36,48 @@ def home(request): "active_productions": active_productions, "completed_projects": completed_projects, "current_time": timezone.now(), + "is_admin": request.session.get('is_studio_admin', False), } return render(request, "core/index.html", context) +def admin_login(request): + """View to enter the unique admin access key.""" + if request.method == "POST": + key = request.POST.get("access_key") + try: + config = StudioConfig.objects.get(id=1) + if key == config.admin_access_key: + request.session['is_studio_admin'] = True + messages.success(request, "Bem-vindo, Comandante do Estúdio!") + return redirect('home') + else: + messages.error(request, "Chave de acesso inválida.") + except StudioConfig.DoesNotExist: + messages.error(request, "Configuração do estúdio não encontrada.") + + return render(request, "core/admin_login.html") + +def admin_logout(request): + """Logout the studio admin.""" + request.session['is_studio_admin'] = False + return redirect('home') + +@studio_admin_required +def asset_library(request): + """View all digital assets (Characters, Props, Environments).""" + assets = CgiAsset.objects.select_related('project').all() + asset_types = { + 'CHAR': assets.filter(asset_type='CHAR'), + 'PROP': assets.filter(asset_type='PROP'), + 'ENV': assets.filter(asset_type='ENV'), + } + + context = { + "assets": assets, + "asset_types": asset_types, + } + return render(request, "core/asset_library.html", context) + def project_detail(request, slug): """Render the detailed pipeline for a specific production.""" project = get_object_or_404(Project.objects.prefetch_related('steps', 'assets'), slug=slug) @@ -34,4 +87,4 @@ def project_detail(request, slug): "steps": project.steps.all(), "assets": project.assets.all(), } - return render(request, "core/project_detail.html", context) \ No newline at end of file + return render(request, "core/project_detail.html", context)