Discuss Scratch

chipmunkmc
Scratch Team
76 posts

Website development

Cloud variables are finally fixed on the scratch-www side of things… unfortunately this does not mean they work just yet. And yes, I implemented a hacky workaround for paths not being supported as cloud hosts, so it should work just fine on the .onion and future .i2p domains.

https://max.chipmunk.land/
hi, this is my signature!
max
Scratch Team
3 posts

Website development

Okay so just a moment ago, the site slowed down to the point of returning 504 Gateway Timed Out, however I seemed to be the only user actually making requests to it the whole time according to nginx logs, so it doesn't seem like a (D)DoS.
Somehow the logs lack any recent, useful info, at least AFAIK.
I'm pretty sure I've seen this happen previously too.
max
Scratch Team
3 posts

Website development

I'd also like to note that I properly configured logging for APIClone so it should be easier to debug things.
Also I've had the timeout issue multiple times on daphne but only once (or twice?) on gunicorn, interestingly.
max
Scratch Team
3 posts

Website development

I also decided to finally set up apiclone on my main PC for development, it was quite simple and I should have done so sooner. This did lead to me catching a bug in apiclone causing the admin panel to be inaccessible though!
Anyway I keep getting this error:
  Your models in app(s): 'djangobb_forum', 'homepage' have changes that are not yet reflected in a migration, and so won't be applied.
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

It's been this way for a while and I've been able to safely ignore it, but it's still quite interesting. It never occurred on my local installation, notably.
Nino
Scratcher
1 post

Website development


move (10) steps
-S0dium-
Scratcher
16 posts

Website development

Nino wrote:


move (10) steps

hey i was

Nino wrote:


move (10) steps

supposed to have the first scratchblock
the
New Scratcher
13 posts

Website development

-S0dium- wrote:

Nino wrote:


move (10) steps

hey i was

Nino wrote:


move (10) steps

supposed to have the first scratchblock

why are they 2.0 scratchblocks? they're supposed to be 3.0 scratchblocks!
medians
Scratcher
20 posts

Website development

lol got so many messages from this topic from before I even joined
aaaaa
New Scratcher
10 posts

Website development

So I've thought about improving theme/skin support on APIClone again, and had some ideas.
Ones I've already had:
  • Change the static file path and have each theme include its own copies of many
  • Ditto but automatically copy files missing in themes to static_prod/
Now some new ones:
  • Each theme simply applies a .css over the page. Easy to implement, easy to distribute themes, and already used for blue.css, but I am unsure how unique selectors are across every page style
  • Ditto but with separate per-page overrides
  • Themes include Python code to control what styesheets are applied to pages and from where. Should be versatile while also supporting small themes nicely.
Misc:
  • Any of these but with scripts too.
  • DjangoBB integration?
  • Template overrides? Nevermind that's probably way too overkill.

Speaking of one-file themes there might be some at https://userstyles.org/styles/browse?search_terms=Scratch
Edit: I realize APIClone's blue color scheme is split into multiple files, oops.

Last edited by chipmunkmc (July 14, 2026 08:05:24)

-S0dium-
Scratcher
16 posts

Website development

aaaaa wrote:

So I've thought about improving theme/skin support on APIClone again, and had some ideas.
Ones I've already had:
[*]Change the static file path and have each theme include its own copies of many
[*]Ditto but automatically copy files missing in themes to static_prod/
Now some new ones:
[*]Each theme simply applies a .css over the page. Easy to implement, easy to distribute themes, and already used for blue.css, but I am unsure how unique selectors are across every page style
[*]Ditto but with separate per-page overrides
[*]Themes include Python code to control what styesheets are applied to pages and from where. Should be versatile while also supporting small themes nicely.
Misc:
[*]Any of these but with scripts too.
[*]DjangoBB integration?
[*]Template overrides? Nevermind that's probably way too overkill.

Speaking of one-file themes there might be some here.

Minor url error
anyway, maybe you can switch the theme in account settings?
Some themes I propose:
The current one (default)
2.0 blue light
3.0 blue light
3.0 purple light
And dark versions from the scratch addons themes
aaaaa
New Scratcher
10 posts

Website development

-S0dium- wrote:

Minor url error
anyway, maybe you can switch the theme in account settings?
Some themes I propose:
The current one (default)
2.0 blue light
3.0 blue light
3.0 purple light
And dark versions from the scratch addons themes

Preferably anonymous users would be able to apply themes too. A while ago I suggested the selector would go on the page footer, and the current implementation does so.
-S0dium-
Scratcher
16 posts

Website development

aaaaa wrote:

-S0dium- wrote:

Minor url error
anyway, maybe you can switch the theme in account settings?
Some themes I propose:
The current one (default)
2.0 blue light
3.0 blue light
3.0 purple light
And dark versions from the scratch addons themes

Preferably anonymous users would be able to apply themes too. A while ago I suggested the selector would go on the page footer, and the current implementation does so.

But it’s just the year that theme is from, and it doesn’t even change much rn
aaaaa
New Scratcher
10 posts

Website development

-S0dium- wrote:

aaaaa wrote:

-S0dium- wrote:

Minor url error
anyway, maybe you can switch the theme in account settings?
Some themes I propose:
The current one (default)
2.0 blue light
3.0 blue light
3.0 purple light
And dark versions from the scratch addons themes

Preferably anonymous users would be able to apply themes too. A while ago I suggested the selector would go on the page footer, and the current implementation does so.

But it’s just the year that theme is from, and it doesn’t even change much rn

For now it can only change pages' structure and apply blue.css on the scratchr2 side, where it is not currently enabled, AFAIK.
Heathercat123
Scratcher
51 posts

Website development

the wrote:

-S0dium- wrote:

Nino wrote:


move (10) steps

hey i was

Nino wrote:


move (10) steps

supposed to have the first scratchblock

why are they 2.0 scratchblocks? they're supposed to be 3.0 scratchblocks!

They're supposed to be the 3.0 blocks on WWW and 2.0 on R2, but that seems to be broken right now

Creator of much of the backend code for this website (the Scratch section, not the rest!) along with contributions from @chipmunkmc.
Heathercat123
Scratcher
51 posts

Website development

aaaaa wrote:


  • Change the static file path and have each theme include its own copies of many
  • Ditto but automatically copy files missing in themes to static_prod/


Or maybe configure nginx so that it checks the styled static directory, which would only include files useful for the theme, and if that returns a 404, fall back to the regular static folder? Is that possible?


  • Each theme simply applies a .css over the page. Easy to implement, easy to distribute themes, and already used for blue.css, but I am unsure how unique selectors are across every page style
  • Ditto but with separate per-page overrides
  • Themes include Python code to control what styesheets[sic] are applied to pages and from where. Should be versatile while also supporting small themes nicely.

Selectors normally don't overlap between pages even if they use a different set of CSS files. For instance, making the bar above forum posts blue affects absolutely nothing outside of the forums.


Edit: I realize APIClone's blue color scheme is split into multiple files, oops.


Yeah, but if I remember correctly, that's just because of the differences between the 2013 and 2015 navbars. The definitions would overlap each other in a way that simply wouldn't work.

Creator of much of the backend code for this website (the Scratch section, not the rest!) along with contributions from @chipmunkmc.
aaaaa
New Scratcher
10 posts

Website development

Heathercat123 wrote:

Or maybe configure nginx so that it checks the styled static directory, which would only include files useful for the theme, and if that returns a 404, fall back to the regular static folder? Is that possible?

Oops, forgot to mention this, sorry. In theory this might be possible to implement with try_files in Nginx.
Still, I'm not sure if requiring web server tricks is ideal. While it's already needed for a scratch-www setup, this would affect scratchr2 as well, and it adds more complexity to the setup.

Maybe it's not a big deal though. It would also be equivalent to the first method on the apiclone side if I understand correctly, and some themes might not even need missing files to be handled.
chipmunkmc
Scratch Team
76 posts

Website development

So there's been a bug causing the scratchr2 splash page to fail to load, and it turns out illegal names caused it:
Internal Server Error: /
Traceback (most recent call last):
  File "/usr/lib/python3.14/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/usr/lib/python3.14/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/apiclone/homepage/views.py", line 146, in HomepageView
    return render(request, "homepage/index.html", context)
  File "/usr/lib/python3.14/site-packages/django/shortcuts.py", line 25, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/lib/python3.14/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/backends/django.py", line 107, in render
    return self.template.render(context)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 172, in render
    return self._render(context)
           ~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 164, in _render
    return self.nodelist.render(context)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/loader_tags.py", line 159, in render
    return compiled_parent._render(context)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 164, in _render
    return self.nodelist.render(context)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/loader_tags.py", line 65, in render
    result = block.nodelist.render(context)
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 327, in render
    return nodelist.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 327, in render
    return nodelist.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/loader_tags.py", line 210, in render
    return template.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 174, in render
    return self._render(context)
           ~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 164, in _render
    return self.nodelist.render(context)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 327, in render
    return nodelist.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 327, in render
    return nodelist.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 243, in render
    nodelist.append(node.render_annotated(context))
                    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/loader_tags.py", line 210, in render
    return template.render(context)
           ~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 174, in render
    return self._render(context)
           ~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 164, in _render
    return self.nodelist.render(context)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 1018, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
                               ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/base.py", line 979, in render_annotated
    return self.render(context)
           ~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3.14/site-packages/django/template/defaulttags.py", line 480, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "/usr/lib/python3.14/site-packages/django/urls/base.py", line 98, in reverse
    resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
  File "/usr/lib/python3.14/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'profile_detail' with arguments '(' ',)' not found. 1 pattern(s) tried: ['users/(?P<username>[\\w-]+)/$']

https://max.chipmunk.land/
hi, this is my signature!
Heathercat123
Scratcher
51 posts

Website development

chipmunkmc wrote:

So there's been a bug causing the scratchr2 splash page to fail to load, and it turns out illegal names caused it:
-snip-


Oh wow, so I really just forgot to check if usernames are valid before registration, oopsies!

Creator of much of the backend code for this website (the Scratch section, not the rest!) along with contributions from @chipmunkmc.
chipmunkmc
Scratch Team
76 posts

Website development

I tried to invite everyone to be a Scdatcher, lets hope it works.
>>> for user in User.objects.filter(groups__name='New Scratchers', userprofile__invited_scratcher=False):
&#8230;     user.userprofile.invited_scratcher = True
&#8230;     user.userprofile.save()
&#8230;

https://max.chipmunk.land/
hi, this is my signature!
Heathercat123
Scratcher
51 posts

Website development

chipmunkmc wrote:

I tried to invite everyone to be a Scdatcher[sic], lets hope it works.
>>> for user in User.objects.filter(groups__name='New Scratchers', userprofile__invited_scratcher=False):
&#8230;     user.userprofile.invited_scratcher = True
&#8230;     user.userprofile.save()
&#8230;

LGTM! The only thing that looks wrong is your spelling of Scratcher

Creator of much of the backend code for this website (the Scratch section, not the rest!) along with contributions from @chipmunkmc.

Powered by DjangoBB