From a9a66fe27e1774e87061383b0777a88f31a5bc34 Mon Sep 17 00:00:00 2001 From: Michael Murtaugh Date: Wed, 22 Jan 2025 17:11:17 +0100 Subject: [PATCH] 2025 call django --- 2025/call/.gitignore | 4 + 2025/call/call/__init__.py | 0 2025/call/call/admin.py | 5 + 2025/call/call/apps.py | 6 + 2025/call/call/forms.py | 14 + 2025/call/call/migrations/0001_initial.py | 25 ++ .../migrations/0002_alter_creature_message.py | 18 + 2025/call/call/migrations/__init__.py | 0 2025/call/call/models.py | 10 + .../static/call/2bitcharactergenerator.js | 394 ++++++++++++++++++ 2025/call/call/static/call/Makefile | 3 + 2025/call/call/static/call/call.html | 118 ++++++ 2025/call/call/static/call/terms.json | 324 ++++++++++++++ 2025/call/call/static/call/terms.yaml | 317 ++++++++++++++ .../static/call/update_terms_yaml_to_json.py | 16 + 2025/call/call/static/call/xpubcharacters.js | 102 +++++ 2025/call/call/templates/call/base.html | 13 + 2025/call/call/templates/call/creature.html | 19 + .../call/templates/call/creature_detail.html | 6 + .../call/templates/call/creature_list.html | 30 ++ 2025/call/call/templates/call/index.html | 146 +++++++ 2025/call/call/tests.py | 3 + 2025/call/call/urls.py | 27 ++ 2025/call/call/views.py | 29 ++ 2025/call/call2025/__init__.py | 0 2025/call/call2025/asgi.py | 16 + 2025/call/call2025/settings.py | 127 ++++++ 2025/call/call2025/urls.py | 26 ++ 2025/call/call2025/wsgi.py | 16 + 2025/call/manage.py | 22 + 30 files changed, 1836 insertions(+) create mode 100644 2025/call/.gitignore create mode 100644 2025/call/call/__init__.py create mode 100644 2025/call/call/admin.py create mode 100644 2025/call/call/apps.py create mode 100644 2025/call/call/forms.py create mode 100644 2025/call/call/migrations/0001_initial.py create mode 100644 2025/call/call/migrations/0002_alter_creature_message.py create mode 100644 2025/call/call/migrations/__init__.py create mode 100644 2025/call/call/models.py create mode 100644 2025/call/call/static/call/2bitcharactergenerator.js create mode 100644 2025/call/call/static/call/Makefile create mode 100644 2025/call/call/static/call/call.html create mode 100644 2025/call/call/static/call/terms.json create mode 100644 2025/call/call/static/call/terms.yaml create mode 100644 2025/call/call/static/call/update_terms_yaml_to_json.py create mode 100644 2025/call/call/static/call/xpubcharacters.js create mode 100644 2025/call/call/templates/call/base.html create mode 100644 2025/call/call/templates/call/creature.html create mode 100644 2025/call/call/templates/call/creature_detail.html create mode 100644 2025/call/call/templates/call/creature_list.html create mode 100644 2025/call/call/templates/call/index.html create mode 100644 2025/call/call/tests.py create mode 100644 2025/call/call/urls.py create mode 100644 2025/call/call/views.py create mode 100644 2025/call/call2025/__init__.py create mode 100644 2025/call/call2025/asgi.py create mode 100644 2025/call/call2025/settings.py create mode 100644 2025/call/call2025/urls.py create mode 100644 2025/call/call2025/wsgi.py create mode 100755 2025/call/manage.py diff --git a/2025/call/.gitignore b/2025/call/.gitignore new file mode 100644 index 0000000..309938f --- /dev/null +++ b/2025/call/.gitignore @@ -0,0 +1,4 @@ +db/ +**/__pycache__/ +media/ + diff --git a/2025/call/call/__init__.py b/2025/call/call/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/2025/call/call/admin.py b/2025/call/call/admin.py new file mode 100644 index 0000000..b42272c --- /dev/null +++ b/2025/call/call/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import Creature + +admin.site.register(Creature) \ No newline at end of file diff --git a/2025/call/call/apps.py b/2025/call/call/apps.py new file mode 100644 index 0000000..9766d9c --- /dev/null +++ b/2025/call/call/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CallConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'call' diff --git a/2025/call/call/forms.py b/2025/call/call/forms.py new file mode 100644 index 0000000..5f054c2 --- /dev/null +++ b/2025/call/call/forms.py @@ -0,0 +1,14 @@ +from django.forms import ModelForm +from call.models import Creature + + +class CreatureForm(ModelForm): + class Meta: + model = Creature + fields = ["image", "caption", "message"] + +class CreatureFormNoImage(ModelForm): + class Meta: + model = Creature + fields = ["caption", "message"] + diff --git a/2025/call/call/migrations/0001_initial.py b/2025/call/call/migrations/0001_initial.py new file mode 100644 index 0000000..439c774 --- /dev/null +++ b/2025/call/call/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 5.1.5 on 2025-01-21 07:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Creature', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(upload_to='creatures')), + ('caption', models.CharField(max_length=255)), + ('created', models.DateTimeField(auto_now_add=True, verbose_name='date created')), + ('updated', models.DateTimeField(auto_now=True, verbose_name='date updated')), + ('message', models.TextField(max_length=512)), + ], + ), + ] diff --git a/2025/call/call/migrations/0002_alter_creature_message.py b/2025/call/call/migrations/0002_alter_creature_message.py new file mode 100644 index 0000000..3e313cd --- /dev/null +++ b/2025/call/call/migrations/0002_alter_creature_message.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.5 on 2025-01-21 07:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('call', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='creature', + name='message', + field=models.TextField(blank=True, max_length=512), + ), + ] diff --git a/2025/call/call/migrations/__init__.py b/2025/call/call/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/2025/call/call/models.py b/2025/call/call/models.py new file mode 100644 index 0000000..462f761 --- /dev/null +++ b/2025/call/call/models.py @@ -0,0 +1,10 @@ +from django.db import models + + +class Creature(models.Model): + image = models.ImageField(upload_to="creatures") + caption = models.CharField(max_length=255) + created = models.DateTimeField("date created", auto_now_add=True) + updated = models.DateTimeField("date updated", auto_now=True) + message = models.TextField(max_length=512, blank=True) + diff --git a/2025/call/call/static/call/2bitcharactergenerator.js b/2025/call/call/static/call/2bitcharactergenerator.js new file mode 100644 index 0000000..0301bc0 --- /dev/null +++ b/2025/call/call/static/call/2bitcharactergenerator.js @@ -0,0 +1,394 @@ +var PARTS_MAX = { + eyes: 12, + mouth: 8, + ears: 6, + torso: 5, + hair: 22, + }; +var gParts = {} +var gColor = 0; +var gColorMode = '012'; + +var showCanvas = document.getElementById('c'); + +var outCanvas = document.getElementById('outc'); +outCanvas.width = 16 * 6; +outCanvas.height = 16 * 1; + + +var ctx = showCanvas.getContext('2d'); +var outCtx = outCanvas.getContext('2d'); + +var outCanvas_gbs_s = document.getElementById("outc_gbs_s") +outCanvas_gbs_s.width = 48 +outCanvas_gbs_s.height = 16 + +var outCanvas_gbs_a = document.getElementById("outc_gbs_a") +outCanvas_gbs_a.width = 96 +outCanvas_gbs_a.height = 16 + +var outCtx_gbs_s = outCanvas_gbs_s.getContext('2d'); +var outCtx_gbs_a = outCanvas_gbs_a.getContext('2d'); + +var a = function(n) { + return n + .split(',') + .map(function(k){ return { x: parseInt(k), f: !!k.match('f')} }); +} +var ANIMS = { + rotate: a("0,2f,1,2"), + run_front: a("0,3,0f,3f"), + run_back: a("1,4,1f,4f"), + run_left: a("2,5"), + run_right: a("2f,5f"), +} +var ANIM_NAMES = Object.keys(ANIMS); +var currentAnimName = "run_front"; + +var gTextures = { loaded: 0, requested: 0 }; + +loadAllTextures(); + +var __appstarted = false; +function loadTexture(key) { + // var tex = new Image(); + var tex = document.querySelector("#all_imgs").querySelector('#img_'+key); + + // tex.src = "./" + key + ".png?v=" + Math.random(); + gTextures.requested++; + gTextures[key] = tex; + + var tex_onload = function() { + gTextures.loaded++; + if(gTextures.loaded === gTextures.requested){ + if(__appstarted){ + updateOutCanvas(); + } else { + startApp(); + } + } else { + document.getElementById('loading').innerText = + "loading... " + gTextures.loaded + " / " + gTextures.requested; + } + } + + if (tex.complete) { + window.setTimeout(tex_onload, 10); + } else { + tex.onload = tex_onload; + } +} + +function loadAllTextures() { + loadTexture("hair"); + loadTexture("base"); + loadTexture("eyes"); + loadTexture("mouth"); + loadTexture("ears"); + loadTexture("torso"); + loadTexture("hands"); +} + +function startApp() { + __appstarted = true; + setupInput("eyes") + setupInput("mouth") + setupInput("ears") + setupInput("torso") + setupInput("hair") + setupColorInput(); + setupColorMode(); + + updateOutCanvas(); + updateAnimBtnText(); + window.setInterval(animate, 16); + + document.getElementById('loading').innerText = ''; + document.getElementById('root').className = ''; +} + +function animate(){ + ctx.clearRect(0, 0, 16, 16); + var t = Date.now ? Date.now() : +(new Date()); + + var nt = parseInt(t / 200) + var anim = ANIMS[currentAnimName]; + var len = anim.length; + + var findex = nt % len; + var frame = anim[findex]; + + ctx.save(); + if(frame.f){ + ctx.translate(16, 0); + ctx.scale(-1, 1); + } + ctx.drawImage(outCanvas, frame.x * 16, 0, 16, 16, 0, 0, 16, 16); + ctx.restore(); +} + + +var animbtn = document.getElementById('animbtn'); +function updateAnimBtnText(){ + animbtn.innerText = currentAnimName.replace("_", " "); +} +animbtn.onclick = function() { + var index = ANIM_NAMES.indexOf(currentAnimName); + currentAnimName = ANIM_NAMES[index + 1] || ANIM_NAMES[0]; + updateAnimBtnText(); +} +showCanvas.onclick = animbtn.onclick; + +// var randomizebtn = document.getElementById('randomizebtn'); +// randomizebtn.onclick = function() { +// var inputs = document.getElementById('inputs').querySelectorAll('input'); + +// for(var i=0; i + + + +xpub call 2025 + + + + + +

XPUB Prospective Student Builder...

+loading... +
+ + +
+ +
HERE CAPTION
+ +
+ + + + + + + +
+ + +
+ + + + + + + + +
+ +
+ + + + +
+
+ export: + default + gbs + gbs anim +
+ +
+ +
+ + + + + + + +
+ + +
+

+ The heart of this webpage is 0x72's 2bitcharactergenerator, found via Everest Pipkin's great tinytools.directory and generously released via a CC0 (public domain) license. As a program XPUB believes in creative expressions as not from scratch, but, like language in general, shared and in conversation with all that's come before it. +

+
+ + + + + + diff --git a/2025/call/call/static/call/terms.json b/2025/call/call/static/call/terms.json new file mode 100644 index 0000000..8d0b1e9 --- /dev/null +++ b/2025/call/call/static/call/terms.json @@ -0,0 +1,324 @@ +{ + "action": [ + "researching", + "studying", + "scanning", + "inflitrating", + "uploading", + "seeding", + "screening", + "spamming", + "tweeting", + "tooting", + "singing", + "feeling", + "listening to", + "playing", + "reading", + "disrupting", + "acting as", + "dancing", + "seeing", + "cooking", + "preaching", + "translating", + "yelling", + "screaming", + "running", + "whistleblowing", + "leaking", + "painting", + "writing", + "laughing at", + "dictating", + "designing", + "destroying", + "showing", + "debating", + "creating", + "performing", + "building", + "hiding", + "surveilling", + "faking", + "banning", + "watching", + "deciding", + "dealing", + "exchanging", + "mediating", + "fighting", + "vandalizing", + "parodying", + "questioning", + "criticizing", + "provoking", + "obscuring", + "shouting on", + "controlling", + "demanding", + "delivering", + "disclosing", + "developing", + "divulging", + "lying about", + "bragging about", + "echoing", + "portraying", + "helping", + "hiding", + "interrupting", + "conspiring", + "sending", + "repairing", + "disagreeing" + ], + "actor": [ + "hipster", + "scener", + "seeder", + "leecher", + "pirate", + "librarian", + "virus", + "AI", + "wizard", + "quant", + "CEO", + "shareholder", + "user", + "stenographer", + "maker", + "artist", + "professional", + "hobbyist", + "amateur", + "teacher", + "student", + "doctor", + "patient", + "public", + "criminal", + "cook", + "editor", + "programmer", + "preacher", + "livecoder", + "individual", + "visitor", + "hacker", + "reader", + "consumer", + "mediator", + "actor", + "builder", + "child", + "adult", + "architect", + "tourist", + "person", + "parent", + "photographer", + "musician", + "designer", + "chatbot", + "regulator", + "dancer", + "developer", + "author", + "robot", + "dog", + "cat", + "judge", + "celebrity", + "computer", + "politician", + "president", + "manager", + "entrepreneur", + "whistleblower", + "infiltrator", + "book binder", + "collective" + ], + "media": [ + "image boards", + "forums", + "warez", + "screens", + "galleries", + "screensavers", + "viruses", + "frequencies", + "files", + "operating systems", + "databases", + "privacy", + "posters", + "cybernetics", + "floppy disks", + "CD-ROMs", + "LaserDiscs", + "apps", + "spam", + "startups", + "manuscripts", + "carpets", + "markets", + "architectures", + "feels", + "books", + "games", + "radio", + "music", + "graffitis", + "blogs", + "theatre", + "woodblocks", + "dances", + "recycling", + "emails", + "food", + "migration", + "magazines", + "maps", + "comics", + "finance", + "teaching", + "memes", + "futures", + "traditions", + "corruption", + "regulation", + "porn", + "webpages", + "vandalism", + "samizdat", + "ethics", + "billboards", + "advertising", + "manifestos", + "leaflets", + "browsers", + "wikis", + "canvases", + "tapes", + "vinyls", + "records", + "synthesizers", + "feeds", + "newspapers", + "HTML pages", + "codex", + "software", + "codes of conduct", + "epubs", + "PDFs", + "NFTs", + "stories", + "dictionaries", + "libraries", + "bugs", + "disagreements" + ], + "prefix": [ + "proto", + "xeno", + "cyber", + "retro", + "pre", + "ante", + "proto", + "post", + "avant", + "neo", + "anti", + "co", + "epi", + "ex", + "extra", + "hyper", + "infra", + "inter", + "macro", + "micro", + "mid", + "mono", + "non", + "multi", + "omni", + "semi", + "sub", + "super", + "trans", + "cross", + "uni", + "minor" + ], + "sort": [ + "bootleg", + "capitalist", + "progressive", + "organic", + "industrial", + "homemade", + "craft", + "AI", + "encrypted", + "inclusive", + "fair", + "transparent", + "command line", + "granular", + "crypto", + "centralised", + "free", + "libre", + "open", + "proprietary", + "DIY", + "DIWO", + "homebrew", + "decentralised", + "closed source", + "binary", + "plaintext", + "federated", + "distributed", + "online", + "offline", + "raw", + "compressed", + "deep", + "dark", + "common", + "shared", + "liberal", + "anarcho-capitalist", + "anarcho-communist", + "anarcho-syndicalist", + "authoritarian", + "capitalist", + "communist", + "marxist", + "apolitical", + "syndicated", + "digital", + "analog", + "bottom-up", + "top-down", + "horizontal", + "vertical", + "agonistic", + "version-controlled", + "feminist", + "decolonial", + "contradictory", + "occasional", + "layered", + "entangled", + "collective", + "complex", + "artificial" + ] +} \ No newline at end of file diff --git a/2025/call/call/static/call/terms.yaml b/2025/call/call/static/call/terms.yaml new file mode 100644 index 0000000..d2c8f23 --- /dev/null +++ b/2025/call/call/static/call/terms.yaml @@ -0,0 +1,317 @@ +action: +- researching +- studying +- scanning +- inflitrating +- uploading +- seeding +- screening +- spamming +- tweeting +- tooting +- singing +- feeling +- listening to +- playing +- reading +- disrupting +- acting as +- dancing +- seeing +- cooking +- preaching +- translating +- yelling +- screaming +- running +- whistleblowing +- leaking +- painting +- writing +- laughing at +- dictating +- designing +- destroying +- showing +- debating +- creating +- performing +- building +- hiding +- surveilling +- faking +- banning +- watching +- deciding +- dealing +- exchanging +- mediating +- fighting +- vandalizing +- parodying +- questioning +- criticizing +- provoking +- obscuring +- shouting on +- controlling +- demanding +- delivering +- disclosing +- developing +- divulging +- lying about +- bragging about +- echoing +- portraying +- helping +- hiding +- interrupting +- conspiring +- sending +- repairing +- disagreeing +actor: +- hipster +- scener +- seeder +- leecher +- pirate +- librarian +- virus +- AI +- wizard +- quant +- CEO +- shareholder +- user +- stenographer +- maker +- artist +- professional +- hobbyist +- amateur +- teacher +- student +- doctor +- patient +- public +- criminal +- cook +- editor +- programmer +- preacher +- livecoder +- individual +- visitor +- hacker +- reader +- consumer +- mediator +- actor +- builder +- child +- adult +- architect +- tourist +- person +- parent +- photographer +- musician +- designer +- chatbot +- regulator +- dancer +- developer +- author +- robot +- dog +- cat +- judge +- celebrity +- computer +- politician +- president +- manager +- entrepreneur +- whistleblower +- infiltrator +- book binder +- collective +media: +- image boards +- forums +- warez +- screens +- galleries +- screensavers +- viruses +- frequencies +- files +- operating systems +- databases +- privacy +- posters +- cybernetics +- floppy disks +- CD-ROMs +- LaserDiscs +- apps +- spam +- startups +- manuscripts +- carpets +- markets +- architectures +- feels +- books +- games +- radio +- music +- graffitis +- blogs +- theatre +- woodblocks +- dances +- recycling +- emails +- food +- migration +- magazines +- maps +- comics +- finance +- teaching +- memes +- futures +- traditions +- corruption +- regulation +- porn +- webpages +- vandalism +- samizdat +- ethics +- billboards +- advertising +- manifestos +- leaflets +- browsers +- wikis +- canvases +- tapes +- vinyls +- records +- synthesizers +- feeds +- newspapers +- HTML pages +- codex +- software +- codes of conduct +- epubs +- PDFs +- NFTs +- stories +- dictionaries +- libraries +- bugs +- disagreements +prefix: +- proto +- xeno +- cyber +- retro +- pre +- ante +- proto +- post +- avant +- neo +- anti +- co +- epi +- ex +- extra +- hyper +- infra +- inter +- macro +- micro +- mid +- mono +- non +- multi +- omni +- semi +- sub +- super +- trans +- cross +- uni +- minor +sort: +- bootleg +- capitalist +- progressive +- organic +- industrial +- homemade +- craft +- AI +- encrypted +- inclusive +- fair +- transparent +- command line +- granular +- crypto +- centralised +- free +- libre +- open +- proprietary +- DIY +- DIWO +- homebrew +- decentralised +- closed source +- binary +- plaintext +- federated +- distributed +- online +- offline +- raw +- compressed +- deep +- dark +- common +- shared +- liberal +- anarcho-capitalist +- anarcho-communist +- anarcho-syndicalist +- authoritarian +- capitalist +- communist +- marxist +- apolitical +- syndicated +- digital +- analog +- bottom-up +- top-down +- horizontal +- vertical +- agonistic +- version-controlled +- feminist +- decolonial +- contradictory +- occasional +- layered +- entangled +- collective +- complex +- artificial diff --git a/2025/call/call/static/call/update_terms_yaml_to_json.py b/2025/call/call/static/call/update_terms_yaml_to_json.py new file mode 100644 index 0000000..af47f44 --- /dev/null +++ b/2025/call/call/static/call/update_terms_yaml_to_json.py @@ -0,0 +1,16 @@ +import click +import yaml +import json + + +@click.command() +@click.argument('input', type=click.File('r')) +@click.argument('output', type=click.File('w')) +@click.argument('indent', type=int, default=2) +def yaml_to_json(input, output, indent): + """Convert a YAML input to JSON output""" + d = yaml.safe_load(input) + json.dump(d, output, indent=indent) + +if __name__ == '__main__': + yaml_to_json() diff --git a/2025/call/call/static/call/xpubcharacters.js b/2025/call/call/static/call/xpubcharacters.js new file mode 100644 index 0000000..cb89ae0 --- /dev/null +++ b/2025/call/call/static/call/xpubcharacters.js @@ -0,0 +1,102 @@ +// function prefixInputWithASpan(input, text){ +// var span = document.createElement("span"); +// span.innerText = text; +// input.parentElement.prepend(span); +// } + +let terms; +let cParts = {}; + +function setupTextInput(key){ + var input = document.getElementById(key + "Input"); + prefixInputWithASpan(input, key) + input.setAttribute('min', 0); + input.setAttribute('max', terms[key].length - 1); + input.value = parseInt(Math.random() * (terms[key].length + 1)); + var inputUpdate = function(e){ + // gParts[key] = parseInt(e.target.value); + // console.log("INPUT UPDATE", e.target.value, gParts); + // updateOutCanvas(); + console.log("INPUT UPDATE", e.target.value); + cParts[key] = parseInt(e.target.value); + updateCaption(); + } + inputUpdate({ target: input }); + input.onchange = inputUpdate; + input.oninput = inputUpdate; +}; + +let grammar = ["actor", "action", "prefix", "sort", "media"]; +function updateCaption () { + let caption = ""; + grammar.forEach(key => { + caption += (caption ? " " : "") + terms[key][cParts[key]]; + }) + document.querySelector("#caption").innerHTML = caption; +} + +async function start () { + const src = document.querySelector("a#terms-data-source").href; + terms = await (await fetch(src)).json(); + console.log("terms", terms); + setupTextInput("action"); + setupTextInput("actor"); + setupTextInput("media"); + setupTextInput("prefix"); + setupTextInput("sort"); +} + +var randomizebtn = document.getElementById('randomizebtn'); +randomizebtn.onclick = function() { + let inputs = document.getElementById('inputs').querySelectorAll('input.g'); + + for(var i=0; i { + if (blob) { + const formdata = new FormData(); + const filename = new Date().toISOString() + ".png"; + formdata.append("image", blob, filename); + formdata.append("caption", document.querySelector("#caption").textContent); + formdata.append("message", form.message.value); + formdata.append("csrfmiddlewaretoken", form.csrfmiddlewaretoken.value); + fetch(form.action, { method:"POST", body: formdata }); + } + }, "image/png"); +} + +document.querySelector("button#send").addEventListener("click", () => { + console.log("SEND"); + const form = document.querySelector("form"); + send(outCanvas, form); +}) \ No newline at end of file diff --git a/2025/call/call/templates/call/base.html b/2025/call/call/templates/call/base.html new file mode 100644 index 0000000..251aa90 --- /dev/null +++ b/2025/call/call/templates/call/base.html @@ -0,0 +1,13 @@ + + + + +{% block title %}xpub call 2025{% endblock %} + + + +{%block content %} +{% endblock %} + + \ No newline at end of file diff --git a/2025/call/call/templates/call/creature.html b/2025/call/call/templates/call/creature.html new file mode 100644 index 0000000..b5435a0 --- /dev/null +++ b/2025/call/call/templates/call/creature.html @@ -0,0 +1,19 @@ +{% load static %} + + + + +xpub call 2025 + + + + + + + +

{{creature.caption}}

+ + + + \ No newline at end of file diff --git a/2025/call/call/templates/call/creature_detail.html b/2025/call/call/templates/call/creature_detail.html new file mode 100644 index 0000000..f38af06 --- /dev/null +++ b/2025/call/call/templates/call/creature_detail.html @@ -0,0 +1,6 @@ +{% extends "call/base.html" %} + +{% block content %} + +

{{object.caption}}

+{% endblock %} \ No newline at end of file diff --git a/2025/call/call/templates/call/creature_list.html b/2025/call/call/templates/call/creature_list.html new file mode 100644 index 0000000..ea07a64 --- /dev/null +++ b/2025/call/call/templates/call/creature_list.html @@ -0,0 +1,30 @@ +{% extends "call/base.html" %} + +{% block content %} +

Creatures

+ + + + + +{% endblock %} \ No newline at end of file diff --git a/2025/call/call/templates/call/index.html b/2025/call/call/templates/call/index.html new file mode 100644 index 0000000..4612bd1 --- /dev/null +++ b/2025/call/call/templates/call/index.html @@ -0,0 +1,146 @@ +{% load static %} + + + + +xpub call 2025 + + + + + +

XPUB Prospective Student Builder...

+loading... +
+ + +
+ +
HERE CAPTION
+ +
+ + + + + + + +
+ + +
+ + + + + + + + +
+ +
+ + + + +
+
+ export: + default + gbs + gbs anim +
+ +
+ +
+ + + + + + + +
+ + +
+

+ The heart of this webpage is 0x72's 2bitcharactergenerator, found via Everest Pipkin's great tinytools.directory and generously released via a CC0 (public domain) license. + As a program XPUB believes in creative expression as not from scratch, and like language, shared and in conversation with all that has come before. +

+
+ +
+ + +
+ +
+ +
+ +
+ {{form.as_p}} + + {% csrf_token %} +
+ +
+ + + + + + + + + + + diff --git a/2025/call/call/tests.py b/2025/call/call/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/2025/call/call/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/2025/call/call/urls.py b/2025/call/call/urls.py new file mode 100644 index 0000000..9ef8ff8 --- /dev/null +++ b/2025/call/call/urls.py @@ -0,0 +1,27 @@ +""" +URL configuration for call2025 project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from call import views +from .views import CreatureIndex, CreatureDetail + + +urlpatterns = [ + path("creatures/", CreatureIndex.as_view(), name="creature_list"), + path("creatures//", CreatureDetail.as_view(), name="creature_detail"), + path('', views.index) +] diff --git a/2025/call/call/views.py b/2025/call/call/views.py new file mode 100644 index 0000000..c67d82a --- /dev/null +++ b/2025/call/call/views.py @@ -0,0 +1,29 @@ +from django.shortcuts import render +from call.forms import CreatureForm +from django.views import generic +from .models import Creature + +# Create your views here. +def index(request): + if request.method == "POST": + print ("post", request.POST) + print ("files", request.FILES) + form = CreatureForm(request.POST, request.FILES) + # form = CreatureFormNo(request.POST, request.FILES) + # formset = AuthorFormSet(request.POST, request.FILES) + if form.is_valid(): + print ("FORM IS VALID") + form.save() + # do something. + else: + print ("FORM NOT VALID") + else: + form = CreatureForm() + return render(request, "call/index.html", {"form": form}) + +class CreatureIndex(generic.ListView): + paginate_by = 20 + model=Creature + +class CreatureDetail(generic.DetailView): + model = Creature diff --git a/2025/call/call2025/__init__.py b/2025/call/call2025/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/2025/call/call2025/asgi.py b/2025/call/call2025/asgi.py new file mode 100644 index 0000000..10e02d3 --- /dev/null +++ b/2025/call/call2025/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for call2025 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/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'call2025.settings') + +application = get_asgi_application() diff --git a/2025/call/call2025/settings.py b/2025/call/call2025/settings.py new file mode 100644 index 0000000..89ed4b5 --- /dev/null +++ b/2025/call/call2025/settings.py @@ -0,0 +1,127 @@ +""" +Django settings for call2025 project. + +Generated by 'django-admin startproject' using Django 5.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-nn7mvrgu6de^%z&6t1usgaji_*59z*v+230tluec-h4fw*n(%i' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'call', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'call2025.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + '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', + ], + }, + }, +] + +WSGI_APPLICATION = 'call2025.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db' / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/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/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +MEDIA_ROOT = 'media/' +MEDIA_URL = 'media/' \ No newline at end of file diff --git a/2025/call/call2025/urls.py b/2025/call/call2025/urls.py new file mode 100644 index 0000000..a0786ee --- /dev/null +++ b/2025/call/call2025/urls.py @@ -0,0 +1,26 @@ +""" +URL configuration for call2025 project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('call.urls')) +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + diff --git a/2025/call/call2025/wsgi.py b/2025/call/call2025/wsgi.py new file mode 100644 index 0000000..ebe3db1 --- /dev/null +++ b/2025/call/call2025/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for call2025 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/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'call2025.settings') + +application = get_wsgi_application() diff --git a/2025/call/manage.py b/2025/call/manage.py new file mode 100755 index 0000000..62d47f3 --- /dev/null +++ b/2025/call/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'call2025.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main()