Compare commits
14 Commits
dotnetflag
...
ご主人様
Author | SHA1 | Date |
---|---|---|
not manx | 2a5ac4b592 | 4 years ago |
not manx | c4e13c4646 | 4 years ago |
not manx | 878250343e | 4 years ago |
not manx | 50718e4ac5 | 4 years ago |
not manx | 0adbfeed83 | 4 years ago |
not manx | a479b49b3f | 4 years ago |
not manx | 65d43fd73d | 5 years ago |
not manx | 497b87c9c3 | 5 years ago |
not manx | 08254eda06 | 5 years ago |
not manx | a31d24c28d | 5 years ago |
not manx | 4214c213e3 | 5 years ago |
not manx | 220e660c84 | 5 years ago |
not manx | e8198bd1e4 | 5 years ago |
not manx | a9e861eefd | 5 years ago |
@ -1,63 +0,0 @@
|
|||||||
###############################################################################
|
|
||||||
# Set default behavior to automatically normalize line endings.
|
|
||||||
###############################################################################
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set default behavior for command prompt diff.
|
|
||||||
#
|
|
||||||
# This is need for earlier builds of msysgit that does not have it on by
|
|
||||||
# default for csharp files.
|
|
||||||
# Note: This is only used by command line
|
|
||||||
###############################################################################
|
|
||||||
#*.cs diff=csharp
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set the merge driver for project and solution files
|
|
||||||
#
|
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
|
||||||
# these files as binary and thus will always conflict and require user
|
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
|
||||||
###############################################################################
|
|
||||||
#*.sln merge=binary
|
|
||||||
#*.csproj merge=binary
|
|
||||||
#*.vbproj merge=binary
|
|
||||||
#*.vcxproj merge=binary
|
|
||||||
#*.vcproj merge=binary
|
|
||||||
#*.dbproj merge=binary
|
|
||||||
#*.fsproj merge=binary
|
|
||||||
#*.lsproj merge=binary
|
|
||||||
#*.wixproj merge=binary
|
|
||||||
#*.modelproj merge=binary
|
|
||||||
#*.sqlproj merge=binary
|
|
||||||
#*.wwaproj merge=binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# behavior for image files
|
|
||||||
#
|
|
||||||
# image files are treated as binary by default.
|
|
||||||
###############################################################################
|
|
||||||
#*.jpg binary
|
|
||||||
#*.png binary
|
|
||||||
#*.gif binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# diff behavior for common document formats
|
|
||||||
#
|
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
|
||||||
# entries below.
|
|
||||||
###############################################################################
|
|
||||||
#*.doc diff=astextplain
|
|
||||||
#*.DOC diff=astextplain
|
|
||||||
#*.docx diff=astextplain
|
|
||||||
#*.DOCX diff=astextplain
|
|
||||||
#*.dot diff=astextplain
|
|
||||||
#*.DOT diff=astextplain
|
|
||||||
#*.pdf diff=astextplain
|
|
||||||
#*.PDF diff=astextplain
|
|
||||||
#*.rtf diff=astextplain
|
|
||||||
#*.RTF diff=astextplain
|
|
@ -1,343 +1,3 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
|
|
||||||
appsettings.json
|
|
||||||
src/config.lisp
|
src/config.lisp
|
||||||
|
\#*#
|
||||||
# User-specific files
|
backups/
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Ll]og/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
/BantFlags/wwwroot/flags/*.png
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUNIT
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# JustCode is a .NET coding add-in
|
|
||||||
.JustCode
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- Backup*.rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
.idea/
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"isRoot": true,
|
|
||||||
"tools": {
|
|
||||||
"dotnet-ef": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"commands": [
|
|
||||||
"dotnet-ef"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
@* (C) Copyright 2019 C-xC-c <boku@plum.moe>
|
|
||||||
This file is part of BantFlags.
|
|
||||||
BantFlags is licensed under the GNU AGPL Version 3.0 or later.
|
|
||||||
see the LICENSE file or <https: //www.gnu.org/licenses/agpl-3.0.en.html /> *@
|
|
||||||
@page
|
|
||||||
@model BantFlags.Pages.IndexModel
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "BantFlags";
|
|
||||||
Layout = "~/Pages/Shared/_Layout.cshtml";
|
|
||||||
}
|
|
||||||
|
|
||||||
<h1>/bant/ Flags</h1>
|
|
||||||
<p>E<span lang="jp">メール</span>: boku (at) plum (dot) moe</p>
|
|
||||||
|
|
||||||
<a href="~/bantflags.user.js">Install Bantflags</a>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<a href="https://nineball.party/srsbsn/3521#bottom">Official Thread</a>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<a asp-page="Upload">Upload Flags</a>
|
|
@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>@ViewData["Title"]</title>
|
|
||||||
@RenderSection("Head", required: false)
|
|
||||||
</head>
|
|
||||||
<body style="text-align: center;">
|
|
||||||
@RenderBody()
|
|
||||||
@RenderSection("Scripts", required: false)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,123 +0,0 @@
|
|||||||
@* (C) Copyright 2019 C-xC-c <boku@plum.moe>
|
|
||||||
This file is part of BantFlags.
|
|
||||||
BantFlags is licensed under the GNU AGPL Version 3.0 or later.
|
|
||||||
see the LICENSE file or <https: //www.gnu.org/licenses/agpl-3.0.en.html /> *@
|
|
||||||
@page
|
|
||||||
@using BantFlags.Data
|
|
||||||
@model BantFlags.UploadModel
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "Upload";
|
|
||||||
Layout = "~/Pages/Shared/_Layout.cshtml";
|
|
||||||
}
|
|
||||||
|
|
||||||
<h1>Upload</h1>
|
|
||||||
<img src="~/montage.png" />
|
|
||||||
<h2 id="message">@Model.Message</h2>
|
|
||||||
<h2>Add a Flag</h2>
|
|
||||||
<form method="post" asp-page-handler="Add" enctype="multipart/form-data">
|
|
||||||
<input type="file" name="upload" />
|
|
||||||
<input type="checkbox" name="gloss" value="true" /><span>Apply Gloss?</span>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<input type="submit" value="Upload Flag" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<h2>Manage Existing Flags</h2>
|
|
||||||
<form method="post">
|
|
||||||
<select name="flag">
|
|
||||||
@foreach (string s in Model.StagedFlags.Names)
|
|
||||||
{
|
|
||||||
<option>@s</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
<input type="text" name="newName" />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<button asp-page-handler="Delete" type="submit">Delete Flag</button>
|
|
||||||
<button asp-page-handler="Rename" type="submit">Rename Flag</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<h2>Commit Changes</h2>
|
|
||||||
<form method="post" asp-page-handler="Commit" enctype="multipart/form-data">
|
|
||||||
<label>Password:</label>
|
|
||||||
<input type="text" name="password" />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<input type="submit" value="Commit Changes" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
@if (Model.StagedFlags.Flags.Any())
|
|
||||||
{
|
|
||||||
<h2>Pending Changes</h2>
|
|
||||||
<form method="post" asp-page-handler="Unstage">
|
|
||||||
<input type="text" name="password" />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<button type="submit">Remove from staging</button>
|
|
||||||
<h3>Deleted Flags</h3>
|
|
||||||
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
|
|
||||||
{
|
|
||||||
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Delete)
|
|
||||||
{
|
|
||||||
<div class="flag">
|
|
||||||
|
|
||||||
<label>@(Model.StagedFlags.Flags[i].Name)</label>
|
|
||||||
<img src="~/flags/@(Model.StagedFlags.Flags[i].Name).png" />
|
|
||||||
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
|
|
||||||
<input type="hidden" name="flags[@i].FlagMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
|
|
||||||
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
<h3>Renamed Flags</h3>
|
|
||||||
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
|
|
||||||
{
|
|
||||||
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Rename)
|
|
||||||
{
|
|
||||||
<div class="flag">
|
|
||||||
<label>@(Model.StagedFlags.Flags[i].Name)</label>
|
|
||||||
<img src="~/flags/@(Model.StagedFlags.Flags[i].OldName).png" />
|
|
||||||
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
|
|
||||||
<input type="hidden" name="flags[@i].FlagMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
|
|
||||||
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
<h3>Added Flags</h3>
|
|
||||||
@for (int i = 0; i < Model.StagedFlags.Flags.Count(); i++)
|
|
||||||
{
|
|
||||||
if (Model.StagedFlags.Flags[i].FlagMethod == Method.Add)
|
|
||||||
{
|
|
||||||
<div class="flag">
|
|
||||||
<label>@(Model.StagedFlags.Flags[i].Name)</label>
|
|
||||||
<img src="~/flags/staging/@(Model.StagedFlags.Flags[i].Name).png" />
|
|
||||||
<input type="hidden" name="flags[@i].Name" value="@Model.StagedFlags.Flags[i].Name" />
|
|
||||||
<input type="hidden" name="flags[@i].FlagMethod" value="@Model.StagedFlags.Flags[i].FlagMethod" />
|
|
||||||
<input type="checkbox" name="flags[@i].IsChecked" value="true" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
|
|
||||||
@section Head {
|
|
||||||
<link rel="stylesheet" href="~/upload.css" />
|
|
||||||
}
|
|
||||||
|
|
||||||
@section Scripts {
|
|
||||||
@* Place flag image inside the <select> because ASP removes "invalid HTML" *@
|
|
||||||
<script>
|
|
||||||
window.addEventListener('load', function (e) {
|
|
||||||
let x = document.getElementsByTagName('select')[0].children
|
|
||||||
Array.prototype.slice.call(x).forEach(function (y) {
|
|
||||||
var name = y.innerHTML;
|
|
||||||
y.innerHTML = "<img src=\"flags/" + name + ".png\">" + name
|
|
||||||
});
|
|
||||||
}, { once: true });
|
|
||||||
</script>
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
@using BantFlags
|
|
||||||
@namespace BantFlags.Pages
|
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -1,3 +0,0 @@
|
|||||||
@{
|
|
||||||
Layout = "_Layout";
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
// (C) Copyright 2019 C-xC-c <boku@plum.moe>
|
|
||||||
// This file is part of BantFlags.
|
|
||||||
// BantFlags is licensed under the GNU AGPL Version 3.0 or later.
|
|
||||||
// see the LICENSE file or <https://www.gnu.org/licenses/>
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace BantFlags
|
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
CreateHostBuilder(args).Build().Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
|
||||||
Host.CreateDefaultBuilder(args)
|
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
|
||||||
{
|
|
||||||
webBuilder.UseStartup<Startup>();
|
|
||||||
})
|
|
||||||
.ConfigureAppConfiguration((host, config) =>
|
|
||||||
{
|
|
||||||
// Explicitly look for appsettings.json in the program's directory
|
|
||||||
config.AddJsonFile(Path.Join(System.AppDomain.CurrentDomain.BaseDirectory + "appsettings.json"), optional: false, reloadOnChange: false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:17777",
|
|
||||||
"sslPort": 44366
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "weatherforecast",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BantFlags": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "weatherforecast",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
// (C) Copyright 2019 C-xC-c <boku@plum.moe>
|
|
||||||
// This file is part of BantFlags.
|
|
||||||
// BantFlags is licensed under the GNU AGPL Version 3.0 or later.
|
|
||||||
// see the LICENSE file or <https://www.gnu.org/licenses/>
|
|
||||||
using BantFlags.Data;
|
|
||||||
using BantFlags.Data.Database;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.FileProviders;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace BantFlags
|
|
||||||
{
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
public Startup(IConfiguration configuration)
|
|
||||||
{
|
|
||||||
Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddControllers().AddNewtonsoftJson(); // So we can format complex datatypes into JSON
|
|
||||||
|
|
||||||
services.AddRazorPages();
|
|
||||||
|
|
||||||
if (!Directory.Exists(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "keys/")))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "keys/"));
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddDataProtection()
|
|
||||||
.SetApplicationName("BantFlags")
|
|
||||||
.PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "keys")));
|
|
||||||
|
|
||||||
services.AddSingleton(new DatabaseService(Configuration.GetSection("dbconfig").Get<DatabaseServiceConfig>()));
|
|
||||||
services.AddSingleton(new Staging(Configuration.GetValue<string>("staging-password")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
|
||||||
{
|
|
||||||
string webroot = Configuration.GetValue<string>("webroot");
|
|
||||||
if (Directory.Exists(webroot))
|
|
||||||
{
|
|
||||||
env.WebRootPath = webroot;
|
|
||||||
env.WebRootFileProvider = new PhysicalFileProvider(env.WebRootPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
|
||||||
{
|
|
||||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
|
||||||
{
|
|
||||||
ServeUnknownFileTypes = true,
|
|
||||||
DefaultContentType = "text/plain"
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
|
||||||
{
|
|
||||||
endpoints.MapRazorPages();
|
|
||||||
endpoints.MapControllers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"AllowedHosts": "*",
|
|
||||||
"dbconfig": {
|
|
||||||
"connectionstring": "Server=localhost;Port=3306;User ID=user;Password=password;Database=bantflags",
|
|
||||||
"poolsize": 2,
|
|
||||||
"boards": [
|
|
||||||
"bant",
|
|
||||||
"nap",
|
|
||||||
"srsbsn"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"webroot": "/var/www/html",
|
|
||||||
"staging-password": "supersecretpassword"
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
# Ignore everything in this directory
|
|
||||||
*
|
|
||||||
# Except this file
|
|
||||||
!.gitignore
|
|
@ -1,4 +0,0 @@
|
|||||||
# Ignore everything in this directory
|
|
||||||
*
|
|
||||||
# Except this file
|
|
||||||
!.gitignore
|
|
Before Width: | Height: | Size: 436 B |
@ -1,28 +0,0 @@
|
|||||||
body {
|
|
||||||
background: #ffe url(fade.png) top center repeat-x;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3 {
|
|
||||||
color: maroon;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
clear: both;
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flag-container {
|
|
||||||
width: 60%;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flag {
|
|
||||||
margin: auto;
|
|
||||||
width: 12%;
|
|
||||||
display: inline-block;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#message {
|
|
||||||
color: #ee0;
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
* /api/flags
|
|
||||||
returns a plaintext list of all the resolved flags, seperated by
|
|
||||||
newline characters (\n). This is maintained by the database service
|
|
||||||
and updated whenever changes are committed to the flag console.
|
|
@ -1,70 +0,0 @@
|
|||||||
* /api/get
|
|
||||||
** Recieved Data
|
|
||||||
All versions of the script send a comma seperated list of post
|
|
||||||
numbers, =post_nrs= and a board =board=. Modern versions of bantflags
|
|
||||||
also send a version number, =version=, which decides how the returned
|
|
||||||
data will be formatted.
|
|
||||||
|
|
||||||
Data looks like this:
|
|
||||||
#+BEGIN_SRC http
|
|
||||||
POST https://flags.plum.moe/api/get
|
|
||||||
Content-Type: application/x-www-form-urlencoded
|
|
||||||
|
|
||||||
post_nrs=12345,12346,14444&board=bant&version=1
|
|
||||||
#+END_SRC
|
|
||||||
** Sent Data
|
|
||||||
*** GetPosts
|
|
||||||
Returns an =IEnumerable<IGrouping<int, DataRow>>= of post numbers and
|
|
||||||
their flags where the post numbers are contained in
|
|
||||||
=post_nrs=. =board= limits the query to only the board we're currently
|
|
||||||
on.
|
|
||||||
*** GetPosts_V1
|
|
||||||
Minimum script version: 0
|
|
||||||
|
|
||||||
Flags are converted from an =IEnumerable<IGrouping<int, DataRow>>= to
|
|
||||||
a =List<Dictionary<string, string>>= by joining the values in the
|
|
||||||
=DataRow= by "||", which are then split and converted into an array by
|
|
||||||
the script.
|
|
||||||
|
|
||||||
We're doing a needless conversion at both ends which slows the whole
|
|
||||||
process down, but it's how extraflags is set up and we need to support
|
|
||||||
it.
|
|
||||||
|
|
||||||
Data looks like this:
|
|
||||||
#+BEGIN_SRC javascript
|
|
||||||
[
|
|
||||||
{
|
|
||||||
{"post_nr": "123"},
|
|
||||||
{"regions": "flag1||flag2||flag3"}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{"post_nr": "456"},
|
|
||||||
{"regions": "flag4||flag3||flag3"}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
*** getPosts_V2
|
|
||||||
Minimum script version: 2
|
|
||||||
|
|
||||||
Flags are converted from an =IEnumerable<IGrouping<int, DataRow>>= to
|
|
||||||
a =Dictionary<int, IEnumerable<string>>= which can then be parsed by
|
|
||||||
the script without any conversion. This format is the same as returned
|
|
||||||
from the database query, sans the extra information returned by a
|
|
||||||
=DataRow=
|
|
||||||
|
|
||||||
Data looks like this:
|
|
||||||
#+BEGIN_SRC javascript
|
|
||||||
[
|
|
||||||
123: [
|
|
||||||
"flag1",
|
|
||||||
"flag2",
|
|
||||||
"flag3"
|
|
||||||
],
|
|
||||||
456: [
|
|
||||||
"flag4",
|
|
||||||
"flag3",
|
|
||||||
"flag3"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
#+END_SRC
|
|
@ -1,18 +0,0 @@
|
|||||||
* /api/post
|
|
||||||
** Recieved Data
|
|
||||||
Data is sent from the script to the backend after a post has been
|
|
||||||
made, containing the post number, =post_nr=, =board= identifier, and
|
|
||||||
selected flags, =regions=. Modern versions of the script also encode a
|
|
||||||
=version= which is used when splitting =regions= into individual flags
|
|
||||||
|
|
||||||
Data looks like this:
|
|
||||||
#+BEGIN_SRC http :pretty
|
|
||||||
POST https://flags/plum.moe/api/post
|
|
||||||
Content-Type: application/x-www-form-urlencoded
|
|
||||||
|
|
||||||
post_nr=12345&board=bant®ions=Patchouli,dount,VIP&version=1
|
|
||||||
#+END_SRC
|
|
||||||
** Sent Data
|
|
||||||
The backend returns either a JSON object of the post, as it would be
|
|
||||||
returned by =/api/get=, or an error message specific to the issue if
|
|
||||||
the form data is invalid.
|
|
@ -1,15 +0,0 @@
|
|||||||
* /Upload
|
|
||||||
The flag console is the preferred way for adding and modifying flags
|
|
||||||
in the database. It provides controls for adding, deleting and
|
|
||||||
renaming flags, all of which are visible before being committed by
|
|
||||||
someone with with password, which is set using the =staging-password=
|
|
||||||
section in =appsettings.json=. Changes may be unstaged on an
|
|
||||||
individual basis, but committed changes must be done all at once.
|
|
||||||
|
|
||||||
Flags have several hard-coded requirements for being uploaded using
|
|
||||||
the console. The image must be 16 by 11 pixels in size, be a PNG file
|
|
||||||
and have a valid PNG header. Names of files must be under 100
|
|
||||||
characters in length, and not contain either "," or
|
|
||||||
"||". Additionally, you cannot name a flag "Empty, or there were
|
|
||||||
errors. Please re-set your flags." as this is used, well, when someone
|
|
||||||
hasn't set their flags right.
|
|
@ -1,102 +0,0 @@
|
|||||||
DROP DATABASE IF EXISTS `bantflags`;
|
|
||||||
CREATE DATABASE `bantflags`;
|
|
||||||
|
|
||||||
USE `bantflags`;
|
|
||||||
|
|
||||||
CREATE USER IF NOT EXISTS flags@localhost IDENTIFIED BY 'default';
|
|
||||||
GRANT ALL PRIVILEGES ON bantflags.* TO flags@localhost;
|
|
||||||
FLUSH PRIVILEGES;
|
|
||||||
|
|
||||||
CREATE TABLE `flags` (
|
|
||||||
`id` int(10) NOT NULL AUTO_INCREMENT,
|
|
||||||
`flag` varchar(100) NOT NULL DEFAULT '0',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `flag` (`flag`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
CREATE TABLE `posts` (
|
|
||||||
`id` int(10) NOT NULL AUTO_INCREMENT,
|
|
||||||
`post_nr` int(10) NOT NULL DEFAULT '0',
|
|
||||||
`board` varchar(10) NOT NULL DEFAULT 'bant',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `post_nr_board` (`post_nr`,`board`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
CREATE TABLE `postflags` (
|
|
||||||
`id` int(10) NOT NULL AUTO_INCREMENT,
|
|
||||||
`post_nr` int(10) NOT NULL DEFAULT '0',
|
|
||||||
`flag` int(10) NOT NULL DEFAULT '0',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `flag` (`flag`),
|
|
||||||
KEY `post_nr` (`post_nr`),
|
|
||||||
CONSTRAINT `flag` FOREIGN KEY (`flag`) REFERENCES `flags` (`id`) ON DELETE CASCADE,
|
|
||||||
CONSTRAINT `post_nr` FOREIGN KEY (`post_nr`) REFERENCES `posts` (`id`)
|
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
CREATE DEFINER=`flags`@`localhost` PROCEDURE `insert_post`(
|
|
||||||
IN `@post_nr` INT,
|
|
||||||
IN `@board` VARCHAR(5)
|
|
||||||
)
|
|
||||||
LANGUAGE SQL
|
|
||||||
NOT DETERMINISTIC
|
|
||||||
CONTAINS SQL
|
|
||||||
SQL SECURITY DEFINER
|
|
||||||
BEGIN
|
|
||||||
INSERT IGNORE INTO `posts` (`post_nr`, `board`) VALUES (`@post_nr`, `@board`);
|
|
||||||
END
|
|
||||||
$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`flags`@`localhost` PROCEDURE `insert_post_flags`(
|
|
||||||
IN `@post_nr` INT,
|
|
||||||
IN `@flag` VARCHAR(100)
|
|
||||||
)
|
|
||||||
LANGUAGE SQL
|
|
||||||
NOT DETERMINISTIC
|
|
||||||
CONTAINS SQL
|
|
||||||
SQL SECURITY DEFINER
|
|
||||||
BEGIN
|
|
||||||
insert into postflags (post_nr, flag) VALUES (
|
|
||||||
(select id from posts where post_nr = `@post_nr`),
|
|
||||||
(select id from flags where flag = `@flag`)
|
|
||||||
);
|
|
||||||
END
|
|
||||||
$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`flags`@`localhost` PROCEDURE `rename_flag`(
|
|
||||||
IN `@old` VARCHAR(100),
|
|
||||||
IN `@new` VARCHAR(100)
|
|
||||||
)
|
|
||||||
LANGUAGE SQL
|
|
||||||
NOT DETERMINISTIC
|
|
||||||
CONTAINS SQL
|
|
||||||
SQL SECURITY DEFINER
|
|
||||||
BEGIN
|
|
||||||
UPDATE flags SET flags.flag = `@new` WHERE flags.flag = `@old`;
|
|
||||||
END
|
|
||||||
$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`flags`@`localhost` PROCEDURE `delete_flag`(
|
|
||||||
IN `@flag` VARCHAR(100)
|
|
||||||
)
|
|
||||||
LANGUAGE SQL
|
|
||||||
NOT DETERMINISTIC
|
|
||||||
CONTAINS SQL
|
|
||||||
SQL SECURITY DEFINER
|
|
||||||
BEGIN
|
|
||||||
DELETE flags.* FROM flags WHERE flags.flag = `@flag`;
|
|
||||||
END
|
|
||||||
$$
|
|
||||||
|
|
||||||
CREATE DEFINER=`flags`@`localhost` PROCEDURE `insert_flag`(
|
|
||||||
IN `@flag` VARCHAR(100)
|
|
||||||
)
|
|
||||||
LANGUAGE SQL
|
|
||||||
NOT DETERMINISTIC
|
|
||||||
CONTAINS SQL
|
|
||||||
SQL SECURITY DEFINER
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO `flags` (`flag`) VALUES (`@flag`);
|
|
||||||
END
|
|
||||||
$$
|
|
||||||
DELIMITER ;
|
|
@ -1,117 +1,93 @@
|
|||||||
* BantFlags
|
* BantFlags
|
||||||
A user script and backend enabling user created flags on [[https://boards.4chan.org/bant][/bant/]],
|
A user script and backend enabling user created flags on [[https://boards.4chan.org/bant][/bant/]],
|
||||||
originally based on [[https://github.com/flaghunters/Extra-Flags-for-4chan][extraflags]].
|
originally based on [[https://github.com/flaghunters/Extra-Flags-for-4chan][extraflags]].
|
||||||
|
|
||||||
[[https://flags.plum.moe/bantflags.user.js][Install bantflags]]
|
[[https://flags.plum.moe/bantflags.user.js][Install bantflags]]
|
||||||
|
|
||||||
** Userscript
|
** Userscript
|
||||||
The userscript uses of ~GM_xmlhttpRequest~ to get and post flags with
|
The userscript uses of ~GM_xmlhttpRequest~ to get and post flags
|
||||||
the backend . A user's flags are stored between pages using
|
with the backend . A user's flags are stored between pages using
|
||||||
~GM_setValue~ and ~GM_getValue~.
|
~GM_setValue~ and ~GM_getValue~, or their GreaseMonkey4
|
||||||
|
equivalents.
|
||||||
|
|
||||||
Old versions of GreaseMonkey will be able to recieve updates to the
|
Old versions of GreaseMonkey will be able to recieve updates to the
|
||||||
script through the ~@updateURL~ and ~@downloadURL~ directives, though
|
script through the ~@updateURL~ and ~@downloadURL~ directives,
|
||||||
these were depricated sometime in GreaseMonkey 3.x and updates are
|
though these were depricated sometime in GreaseMonkey 3.x and
|
||||||
only checked from the location the script was downloaded from so be
|
updates are only checked from the location the script was
|
||||||
careful where you upload links.
|
downloaded from so be careful where you upload links.
|
||||||
|
|
||||||
On self hosting, changing ~back_end~ to your domain /should/ be all
|
On self hosting, changing ~back_end~ to your domain /should/ be all
|
||||||
you need to do, but don't take this as fact. I haven't tested the
|
you need to do, but don't take this as fact.
|
||||||
example nginx config.
|
|
||||||
|
|
||||||
The userscript has been designed specifically to target ECMAScript
|
The userscript has been designed specifically to target ECMAScript
|
||||||
2015 (ES6), making liberal use of arrow functions, and const/let
|
2015 (ES6), making liberal use of arrow functions, and const/let
|
||||||
declarations. Update your hecking browser.
|
declarations. Update your hecking browser.
|
||||||
|
|
||||||
** Backend
|
** Backend
|
||||||
*** Prerequisites
|
*** Prerequisites
|
||||||
- .NET Core 3.1
|
- I use SBCL
|
||||||
- MariaDB / MySQL
|
- Some mysql, I use Mariadb
|
||||||
|
- Quicklisp
|
||||||
*** .NET dependancies
|
*** Dependancies
|
||||||
- Nito.AsyncEX
|
- hunchentoot
|
||||||
- Newtonsoft.Json
|
- [[https://github.com/C-xC-c/hunchenhelpers][hunchenhelpers]], my hunchentoot helper library (yes I'm proud of
|
||||||
- MySql.Data
|
the name)
|
||||||
- Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
- clsql
|
||||||
- Microsoft.AspNetCore.StaticFiles
|
- jonathan, the JSON encoder/decoder
|
||||||
- Microsoft.AspNetCore.Razor
|
- cl-ppcre
|
||||||
- Microsoft.EntityFrameworkCore.SqlServer
|
|
||||||
- Microsoft.EntityFrameworkCore.Tools
|
|
||||||
- Magick.NET-Q8-AnyCPU
|
|
||||||
|
|
||||||
*** Setup
|
*** Setup
|
||||||
1) [[https://dotnet.microsoft.com/download/dotnet-core][Install .NET Core]]
|
1. clone the project
|
||||||
2) Clone and build the BantFlags solution.
|
2. Symlink src/ to your ~/quicklisp/local-projects
|
||||||
3) Create the database using [[https://github.com/C-xC-c/BantFlags/blob/master/Environment/database.sql][database.sql]].
|
3. Move ~src/config.example.org~ to ~src/config.org~ and change it
|
||||||
- *Change the password*.
|
to whatever your settings are.
|
||||||
4) configure ~BantFlags/appsettings.example.json~ with your connection
|
4. Initialise the database by doing something like ~mysql <<
|
||||||
string and webroot (where you'll serve the flags from *without a
|
env/database.sql~, This will create all the tables you will
|
||||||
trailing slash*) and rename it to ~appsettings.json~
|
need, plus an entry for the ~`empty flag`~
|
||||||
- [[./BantFlags/appsettings.example.json][example appsettings.json]]
|
5. Type the following into your repl:
|
||||||
- ASP.NET Core applications look for a folder called ~wwwroot~ in
|
#+BEGIN_SRC lisp
|
||||||
the same directory as the application for static files. However
|
(ql:quickload :bantflags)
|
||||||
you can choose to logically seperate these by providing a vaild
|
(bantflags:main)
|
||||||
directory to ~webroot~.
|
#+END_SRC
|
||||||
- That is to say, if the bantflags application is in
|
6. To use bantflags as a Systemd service, I have included an
|
||||||
~/var/www/bantflags/BantFlags.dll~, the program will look for
|
example service and an ~init.el~ file for the service to run,
|
||||||
the folder ~/var/www/bantflags/wwwroot/~ to host static content,
|
since Systemd will automatically kill it if you just eval
|
||||||
or whatever directory is provided to ~wwwroot~.
|
~bantflags:main~.
|
||||||
5) If you're hosting on your GNU/Linux distribution of choice, Create a
|
You will almost certainly have several issues building clsql, the
|
||||||
folder called ~keys~ in the same directory as the bantflags
|
database connector used. I've [[https://plum.moe/words/bludgeoning-clsql-and-mariadb.html][written a blog post]] on some of the
|
||||||
executable.
|
issues I've encountered personally, but there's no guarantee it'll
|
||||||
- E.G. ~/var/www/bantflags/keys/~
|
work. Piece of shit.
|
||||||
- This is because ASP.NET Core uses some cryptic bullshit anti
|
|
||||||
forgery token when processing HTML forms, and it's unable to
|
|
||||||
persistantly store the decryption keys in memory on
|
|
||||||
GNU/Linux. This directory will store said keys when you or
|
|
||||||
users upload flags to /upload. The path uses
|
|
||||||
~AppDomain.CurrentDomain.BaseDirectory~ internally,
|
|
||||||
I.E. wherever the program is.
|
|
||||||
6) Add flags to the backend by uploading them to the flag console (/Upload).
|
|
||||||
- Flags must be 16x11 pixels and under 15kb. Their names must not
|
|
||||||
exceed 100 characters and cannot contain either "||" or ",".
|
|
||||||
7) Configure your webserver of choice to forward requests to kestral
|
|
||||||
- [[https://github.com/C-xC-c/BantFlags/blob/master/Environment/nginx.conf][Example nginx config.]]
|
|
||||||
8) Run with ~dotnet BantFlags.dll~ or create a service to run it as a
|
|
||||||
daemon.
|
|
||||||
- [[https://github.com/C-xC-c/BantFlags/blob/master/Environment/bantflags.service][Example systemd service.]]
|
|
||||||
9) ???
|
|
||||||
10) profit.
|
|
||||||
|
|
||||||
*** Database
|
*** Database
|
||||||
Tables look like this:
|
Tables look like this:
|
||||||
|
|
||||||
*posts*
|
*posts*
|
||||||
| id | post_nr | board |
|
| id | post_nr | board |
|
||||||
| 1 | 12345 | bant |
|
| 1 | 12345 | bant |
|
||||||
| 2 | 56789 | bant |
|
| 2 | 56789 | bant |
|
||||||
*flags*
|
*flags*
|
||||||
| id | flag |
|
| id | flag |
|
||||||
| 1 | patchouli |
|
| 1 | patchouli |
|
||||||
| 2 | chen |
|
| 2 | chen |
|
||||||
*postflags*
|
*postflags*
|
||||||
| id | post_nr | flag |
|
| id | post_nr | flag |
|
||||||
| 1 | 1 | 1 |
|
| 1 | 1 | 1 |
|
||||||
| 2 | 1 | 2 |
|
| 2 | 1 | 2 |
|
||||||
| 2 | 2 | 2 |
|
| 2 | 2 | 2 |
|
||||||
where ~post_nr~ and ~flag~ in *postflags* are the id fields in their
|
where ~post_nr~ and ~flag~ in *postflags* are the id fields in their
|
||||||
respective tables.
|
respective tables.
|
||||||
*** API
|
*** API
|
||||||
The backend exposes three endpoints for the userscript to get and post
|
The backend exposes three endpoints for the userscript to get and
|
||||||
flags. Flags themselves are hosted from the ~flags/~ directory. This
|
post flags. Flags themselves are hosted from ~flags/~ which is
|
||||||
will be whatever value you gave to ~webroot~ (or
|
~www-root/flags/~ from ~config.lisp~ on the filesystem
|
||||||
~/path/to/bantflags/wwwroot/~ if no value is provided) + ~flags/~.
|
|
||||||
|
|
||||||
| route | purpse |
|
|
||||||
|------------+--------------------------------------------|
|
|
||||||
| /api/get | Get flags using post numbers in the thread |
|
|
||||||
| /api/post | Add flags to the database |
|
|
||||||
| /api/flags | List the flags we support |
|
|
||||||
| /flags/* | The flag images |
|
|
||||||
|
|
||||||
** Backwards Compatibility
|
| route | purpse |
|
||||||
The API is 1:1 compatable with all previous versions of
|
|------------+--------------------------------------------|
|
||||||
bantflags. Further improvements are achieved by encoding a ~version~
|
| /api/get | Get flags using post numbers in the thread |
|
||||||
variable when poking endpoints which allows for breaking changes in
|
| /api/post | Add flags to the database |
|
||||||
the script and backend while guaranteeing data can be parsed on both
|
| /api/flags | List the flags we support |
|
||||||
ends. See [[https://github.com/C-xC-c/BantFlags/tree/master/Docs/][Docs/{endpoint}]] for changes and compatibility.
|
| /flags/* | The flag images |
|
||||||
|
** Notes
|
||||||
|
You will get an error like =Recursive lock attempt #<SB-THREAD:MUTEX
|
||||||
|
"global-message-log-lock" owner: #<SB-THREAD:THREAD
|
||||||
|
"hunchentoot-worker-127.0.0.1:54454" RUNNING {1001DED5E3}>>.= if you
|
||||||
|
try and log to a file that doesn't exist / you don't have permissions
|
||||||
|
to read/write.
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=bantflags backend
|
Description=bantflags serb
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
# Set to the location of the application
|
# Set to the location of the application
|
||||||
WorkingDirectory=/etc/bantflags
|
WorkingDirectory=/var/www/bantflags/src/
|
||||||
ExecStart=/usr/bin/dotnet /etc/bantflags/BantFlags.dll
|
ExecStart=/usr/bin/env sbcl --load init.el
|
||||||
Restart=always
|
Restart=always
|
||||||
# restarts 10 seconds after it goes bang
|
# restarts 10 seconds after it goes bang
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
KillSignal=SIGINT
|
KillSignal=SIGINT
|
||||||
SyslogIdentifier=bantflags
|
SyslogIdentifier=bantflags
|
||||||
User=www-data
|
User=nginx
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
@ -0,0 +1,36 @@
|
|||||||
|
DROP DATABASE IF EXISTS `bantflags`;
|
||||||
|
CREATE DATABASE `bantflags`;
|
||||||
|
|
||||||
|
CREATE USER IF NOT EXISTS flags@localhost IDENTIFIED BY 'default';
|
||||||
|
GRANT ALL PRIVILEGES ON bantflags.* TO flags@localhost;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
||||||
|
USE `bantflags`;
|
||||||
|
|
||||||
|
CREATE TABLE `flags` (
|
||||||
|
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`flag` varchar(100) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `flag` (`flag`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
CREATE TABLE `posts` (
|
||||||
|
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`post_nr` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`board` varchar(10) NOT NULL DEFAULT 'bant',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `post_nr_board` (`post_nr`,`board`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
CREATE TABLE `postflags` (
|
||||||
|
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`post_nr` int(10) NOT NULL DEFAULT '0',
|
||||||
|
`flag` int(10) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `flag` (`flag`),
|
||||||
|
KEY `post_nr` (`post_nr`),
|
||||||
|
CONSTRAINT `flag` FOREIGN KEY (`flag`) REFERENCES `flags` (`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `post_nr` FOREIGN KEY (`post_nr`) REFERENCES `posts` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
INSERT INTO `flags` (`flag`) VALUES ('empty, or there were errors. Re-set your flags.');
|
@ -1,6 +1,14 @@
|
|||||||
|
(in-package #:bantflags)
|
||||||
|
|
||||||
(defvar config
|
(defvar config
|
||||||
'((boards "bant")
|
'((boards ("bant" "uhh"))
|
||||||
(staging-password "not implemented")
|
(staging-password "not implemented")
|
||||||
(db-conn "bantflags" "flags" "default")
|
(db-conn ("localhost" "bantflags" "flags" "default"))
|
||||||
(poolsize 3)
|
(poolsize 3)
|
||||||
(www-root #p"/path/to/files/")))
|
(www-root #p"/path/to/files/")
|
||||||
|
(port 4242)
|
||||||
|
;; These can be a file or stream, make them nil to disable logging
|
||||||
|
;; If the file can't be accessed, throws a weird error. See
|
||||||
|
;; README.org
|
||||||
|
(access-log *standard-output*)
|
||||||
|
(error-log #p"/path/to/error/log/")))
|
||||||
|
@ -1,59 +1,47 @@
|
|||||||
|
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
|
||||||
|
;; This file is part of bantflags.
|
||||||
|
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
|
||||||
|
;; see the LICENSE file or <https://www.gnu.org/licenses/>
|
||||||
|
(in-package #:bantflags)
|
||||||
|
|
||||||
;; Databases in common lisp are the fucking worst.
|
;; Databases in common lisp are the fucking worst.
|
||||||
;; Don't even bother.
|
;; Don't even bother.
|
||||||
|
|
||||||
;; Comparing strings with both
|
;; We're comparing strings
|
||||||
(defparameter *flags* (make-hash-table :test 'equal))
|
(defparameter *flags* (make-hash-table :test 'equal))
|
||||||
(defparameter *boards* (make-hash-table :test 'equal))
|
(defparameter *boards* (make-hash-table :test 'equal))
|
||||||
(defparameter *flags-txt* nil)
|
(defparameter *flags-txt* nil)
|
||||||
(defparameter conn-str nil)
|
(defparameter conn nil)
|
||||||
|
|
||||||
(defvar get-posts-sql "SELECT posts.post_nr, flags.flag from flags left join postflags on (postflags.flag = flags.id) left join posts on (postflags.post_nr = posts.id) where posts.post_nr in (~{'~a'~^,~}) and posts.board = '~a';")
|
|
||||||
|
|
||||||
(defun fuck-you-fukamachi (conn |;_;|)
|
(defparameter get-posts-sql "SELECT posts.post_nr, flags.flag from flags left join postflags on (postflags.flag = flags.id) left join posts on (postflags.post_nr = posts.id) where posts.post_nr in (~{'~a'~^,~}) and posts.board = '~a';")
|
||||||
"What the fuck is going on with what dbi:fetch returns? why is it a
|
|
||||||
fucking list with the database columns as a symbols with pipes around
|
|
||||||
them? How in the dicking shit am I supposed to use :|post_nr| 1234 in
|
|
||||||
any useful or practical way? Why does this fucking Wumpus of a human
|
|
||||||
being Fukamachi feel the need to duplicate so much data? Don't get me
|
|
||||||
wrong, clsql is easily worse to work with, but at least it was fucking
|
|
||||||
smart enough to make the database fields into (values rows columns)"
|
|
||||||
(mapcar (lambda (x) (list (nth 1 x) (nth 3 x)))
|
|
||||||
(dbi:fetch-all (dbi:execute (dbi:prepare conn |;_;|)))))
|
|
||||||
|
|
||||||
(defmacro dbfun (name &rest body)
|
(defmacro dbfun (name &rest body)
|
||||||
`(defun ,name ,(car body)
|
`(defun ,name ,(car body)
|
||||||
(dbi:with-connection (conn :mysql
|
(clsql:with-database (db conn :database-type :mysql :pool t)
|
||||||
:database-name (car conn-str)
|
,@(cdr body))))
|
||||||
:username (nth 1 conn-str)
|
|
||||||
:password (nth 2 conn-str))
|
|
||||||
(dbi:do-sql conn "set names 'utf8';") ;; I fucking hate computers
|
|
||||||
,@(cdr body))))
|
|
||||||
|
|
||||||
(defun flag-id (flag)
|
(defun flag-id (flag)
|
||||||
(gethash flag *flags*))
|
(gethash flag *flags*))
|
||||||
|
|
||||||
(dbfun ping ()
|
|
||||||
(dbi:ping conn))
|
|
||||||
|
|
||||||
(dbfun insert-post (post_nr board flags)
|
(dbfun insert-post (post_nr board flags)
|
||||||
(dbi:do-sql conn
|
(clsql:execute-command (format nil "insert ignore into posts (post_nr, board) values (~a, '~a');" post_nr board) :database db)
|
||||||
(format nil "insert ignore into posts (post_nr, board) values (~a, '~a');" post_nr board))
|
(let ((post-id (caar (clsql:query (format nil "select id from posts where post_nr = ~a and board = '~a';" post_nr board) :database db))))
|
||||||
(let ((post-id (cadr (dbi:fetch (dbi:execute (dbi:prepare conn (format nil "select id from posts where post_nr = ~a and board = '~a';" post_nr board)))))))
|
(clsql:execute-command
|
||||||
(dbi:do-sql conn
|
(with-output-to-string (s)
|
||||||
(with-output-to-string (s)
|
(format s "insert into postflags (post_nr, flag) values")
|
||||||
(format s "insert into postflags (post_nr, flag) values")
|
(loop for flag in (butlast flags) ;; The last flag needs a semi-colon instead of a comma
|
||||||
(loop for flag in (butlast flags)
|
do (format s "(~a,~a)," post-id (flag-id flag)))
|
||||||
do (format s "(~a,~a)," post-id (flag-id flag)))
|
(format s "(~a,~a);" post-id (flag-id (car (last flags)))))
|
||||||
(format s "(~a,~a);" post-id (flag-id (car (last flags))))))))
|
:database db)))
|
||||||
|
|
||||||
(dbfun get-posts (posts board)
|
(dbfun get-posts (posts board)
|
||||||
(let ((result (fuck-you-fukamachi conn (format nil get-posts-sql posts board)))
|
(let ((result (clsql:query (format nil get-posts-sql posts board) :database db))
|
||||||
(table (make-hash-table)))
|
(table (make-hash-table)))
|
||||||
(loop for (post_nr . flag) in result do
|
(loop for (post_nr . flag) in (reverse result) do
|
||||||
(unless (gethash post_nr table)
|
(unless (gethash post_nr table)
|
||||||
(setf (gethash post_nr table) '()))
|
(setf (gethash post_nr table) '()))
|
||||||
(push (car flag) (gethash post_nr table)))
|
(push (car flag) (gethash post_nr table)))
|
||||||
(jojo:to-json table)))
|
(jojo:to-json table)))
|
||||||
|
|
||||||
(dbfun get-flags ()
|
(dbfun get-flags ()
|
||||||
(fuck-you-fukamachi conn "select flags.id, flags.flag from flags"))
|
(clsql:query "select flags.id, flags.flag from flags" :database db))
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
;; This needs to be run with a lisp started in the same directory as
|
||||||
|
;; bantflags
|
||||||
|
(push (truename ".") ql:*local-project-directories*)
|
||||||
|
(ql:register-local-projects)
|
||||||
|
(ql:quickload :bantflags)
|
||||||
|
|
||||||
|
(bantflags:main)
|
||||||
|
(hunchentoot:start bantflags:*serb*)
|
||||||
|
(loop (sleep 43200) (gc :full t))
|
@ -1,58 +1,53 @@
|
|||||||
|
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
|
||||||
|
;; This file is part of bantflags.
|
||||||
|
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
|
||||||
|
;; see the LICENSE file or <https://www.gnu.org/licenses/>
|
||||||
|
(in-package :bantflags)
|
||||||
|
|
||||||
(defun init ()
|
(defun init ()
|
||||||
(set-db-conn)
|
(assert (not (null config)))
|
||||||
(dotimes (_ (cconf 'poolsize))
|
(setf conn (conf 'db-conn))
|
||||||
(dbi:connect-cached :mysql
|
(loop repeat (conf 'poolsize)
|
||||||
:database-name (car conn-str)
|
do ;; This doesn't work lole
|
||||||
:username (nth 1 conn-str)
|
(clsql:connect conn :database-type :mysql :pool t :if-exists :new))
|
||||||
:password (nth 2 conn-str)))
|
|
||||||
(ping) ;; test db conn
|
|
||||||
(set-boards)
|
(set-boards)
|
||||||
(set-flags)
|
(set-flags)
|
||||||
(defvar +serb+ (make-instance 'hunchentoot:easy-acceptor
|
(defvar *serb* (make-instance 'hunchentoot:easy-acceptor
|
||||||
:port 4242
|
:port (conf 'port)
|
||||||
:document-root (cconf 'www-root)))
|
:address "127.0.0.1" ;; localhost
|
||||||
(hunchentoot:start +serb+))
|
:document-root (conf 'www-root)
|
||||||
|
:access-log-destination (conf 'access-log)
|
||||||
|
:message-log-destination (conf 'error-log))))
|
||||||
|
|
||||||
(defun main ()
|
(defun main ()
|
||||||
(handler-case (init)
|
(handler-case (init)
|
||||||
(error (c)
|
(error (c)
|
||||||
(format t "Init fucked up, exiting ~a" c)
|
(format t "Init fucked up, exiting ~a" c)
|
||||||
(return-from main)))
|
(return-from main)))
|
||||||
(loop (sleep 43200) (gc :full t)))
|
(handler-case (hunchentoot:start *serb*)
|
||||||
|
(error (c)
|
||||||
|
(format t "couldn't start serb: ~a" c)
|
||||||
|
(return-from main))))
|
||||||
|
|
||||||
(defmethod hunchentoot:acceptor-status-message (acceptor (http-status-code (eql 404)) &key)
|
(defmethod hunchentoot:acceptor-status-message (acceptor (http-status-code (eql 404)) &key)
|
||||||
(format nil ""))
|
(format nil "")) ;; Empty 404 page
|
||||||
|
|
||||||
(defmacro handle (method uri params &body body)
|
|
||||||
`(hunchentoot:define-easy-handler ,uri ,params
|
|
||||||
(unless (eq ,method (hunchentoot:request-method*))
|
|
||||||
(setf (hunchentoot:return-code*) hunchentoot:+http-not-found+)
|
|
||||||
(hunchentoot:abort-request-handler))
|
|
||||||
,@body))
|
|
||||||
|
|
||||||
(handle :post (api-post :uri "/api/post")
|
(henh:handle :post (api-post :uri "/api/post") @json
|
||||||
(post_nr regions board version)
|
(post_nr regions board version)
|
||||||
(setf (hunchentoot:content-type*) "application/json")
|
(multiple-value-bind (result msg) (insert-post-p post_nr (cl-ppcre:split "," regions) board)
|
||||||
(let ((separator (if (< 1 (get-version version)) "," "||")))
|
(cond
|
||||||
(multiple-value-bind (result msg) (post-valid-p post_nr regions board separator)
|
(result
|
||||||
(cond
|
(insert-post post_nr board msg)
|
||||||
(result
|
(format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg)) ;; This makes JSON
|
||||||
(insert-post post_nr board msg)
|
(t (format nil "{\"Error\": \"~a\"}~%" msg)))))
|
||||||
(format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg))
|
|
||||||
(t
|
|
||||||
(format nil "{\"Error\": \"~a\"}~%" msg))))))
|
|
||||||
|
|
||||||
(handle :post (api-get :uri "/api/get")
|
(henh:handle :post (api-get :uri "/api/get") @json
|
||||||
(post_nrs board version)
|
(post_nrs board version)
|
||||||
(@json tbnl:*reply*)
|
(setf post_nrs (cl-ppcre:split "," post_nrs))
|
||||||
(setf post_nrs (str:split "," post_nrs))
|
(if (get-posts-p post_nrs board)
|
||||||
(cond
|
(format nil "~a~%" (get-posts post_nrs board))
|
||||||
((and (loop for x in post_nrs always (post-number-p x))
|
(t (format nil "{[\"~a\"]}~%" "bad"))))
|
||||||
(boardp board))
|
|
||||||
(format nil "~a~%" (get-posts post_nrs board)))
|
|
||||||
(t (format nil "~a~%" "bad"))))
|
|
||||||
|
|
||||||
(handle :get (api-flags :uri "/api/flags")
|
(henh:handle :get (api-flags :uri "/api/flags") @plain
|
||||||
()
|
()
|
||||||
(@plain tbnl:*reply*)
|
|
||||||
(format nil "~a~%" *flags-txt*))
|
(format nil "~a~%" *flags-txt*))
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
(defpackage #:bantflags
|
||||||
|
(:use #:cl)
|
||||||
|
(:export :init
|
||||||
|
:*serb*))
|
Loading…
Reference in new issue