Compare commits
1 Commits
ご主人様
...
dotnetflag
Author | SHA1 | Date |
---|---|---|
not manx | 7129d0375c | 4 years ago |
@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# 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,3 +1,343 @@
|
|||||||
|
## 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
|
||||||
\#*#
|
|
||||||
backups/
|
# User-specific files
|
||||||
|
*.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
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
@* (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>
|
@ -0,0 +1,13 @@
|
|||||||
|
<!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>
|
@ -0,0 +1,123 @@
|
|||||||
|
@* (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>
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
@using BantFlags
|
||||||
|
@namespace BantFlags.Pages
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -0,0 +1,3 @@
|
|||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
// (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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
// (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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
After Width: | Height: | Size: 436 B |
@ -0,0 +1,28 @@
|
|||||||
|
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;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
* /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.
|
@ -0,0 +1,70 @@
|
|||||||
|
* /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
|
@ -0,0 +1,18 @@
|
|||||||
|
* /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.
|
@ -0,0 +1,15 @@
|
|||||||
|
* /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,16 +1,16 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=bantflags serb
|
Description=bantflags backend
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
# Set to the location of the application
|
# Set to the location of the application
|
||||||
WorkingDirectory=/var/www/bantflags/src/
|
WorkingDirectory=/etc/bantflags
|
||||||
ExecStart=/usr/bin/env sbcl --load init.el
|
ExecStart=/usr/bin/dotnet /etc/bantflags/BantFlags.dll
|
||||||
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=nginx
|
User=www-data
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
@ -0,0 +1,102 @@
|
|||||||
|
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,93 +1,118 @@
|
|||||||
|
* DotnetFlags
|
||||||
|
This branch exists as an archive of bantflags before it was rewritten
|
||||||
|
in Common Lisp. The code here still works but is unmaintained.
|
||||||
* 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
|
The userscript uses of ~GM_xmlhttpRequest~ to get and post flags with
|
||||||
with the backend . A user's flags are stored between pages using
|
the backend . A user's flags are stored between pages using
|
||||||
~GM_setValue~ and ~GM_getValue~, or their GreaseMonkey4
|
~GM_setValue~ and ~GM_getValue~.
|
||||||
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,
|
script through the ~@updateURL~ and ~@downloadURL~ directives, though
|
||||||
though these were depricated sometime in GreaseMonkey 3.x and
|
these were depricated sometime in GreaseMonkey 3.x and updates are
|
||||||
updates are only checked from the location the script was
|
only checked from the location the script was downloaded from so be
|
||||||
downloaded from so be careful where you upload links.
|
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.
|
you need to do, but don't take this as fact. I haven't tested the
|
||||||
|
example nginx config.
|
||||||
The userscript has been designed specifically to target ECMAScript
|
|
||||||
2015 (ES6), making liberal use of arrow functions, and const/let
|
The userscript has been designed specifically to target ECMAScript
|
||||||
declarations. Update your hecking browser.
|
2015 (ES6), making liberal use of arrow functions, and const/let
|
||||||
|
declarations. Update your hecking browser.
|
||||||
|
|
||||||
** Backend
|
** Backend
|
||||||
*** Prerequisites
|
*** Prerequisites
|
||||||
- I use SBCL
|
- .NET Core 3.1
|
||||||
- Some mysql, I use Mariadb
|
- MariaDB / MySQL
|
||||||
- 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. clone the project
|
1) [[https://dotnet.microsoft.com/download/dotnet-core][Install .NET Core]]
|
||||||
2. Symlink src/ to your ~/quicklisp/local-projects
|
2) Clone and build the BantFlags solution.
|
||||||
3. Move ~src/config.example.org~ to ~src/config.org~ and change it
|
3) Create the database using [[https://github.com/C-xC-c/BantFlags/blob/master/Environment/database.sql][database.sql]].
|
||||||
to whatever your settings are.
|
- *Change the password*.
|
||||||
4. Initialise the database by doing something like ~mysql <<
|
4) configure ~BantFlags/appsettings.example.json~ with your connection
|
||||||
env/database.sql~, This will create all the tables you will
|
string and webroot (where you'll serve the flags from *without a
|
||||||
need, plus an entry for the ~`empty flag`~
|
trailing slash*) and rename it to ~appsettings.json~
|
||||||
5. Type the following into your repl:
|
- [[./BantFlags/appsettings.example.json][example appsettings.json]]
|
||||||
#+BEGIN_SRC lisp
|
- ASP.NET Core applications look for a folder called ~wwwroot~ in
|
||||||
(ql:quickload :bantflags)
|
the same directory as the application for static files. However
|
||||||
(bantflags:main)
|
you can choose to logically seperate these by providing a vaild
|
||||||
#+END_SRC
|
directory to ~webroot~.
|
||||||
6. To use bantflags as a Systemd service, I have included an
|
- That is to say, if the bantflags application is in
|
||||||
example service and an ~init.el~ file for the service to run,
|
~/var/www/bantflags/BantFlags.dll~, the program will look for
|
||||||
since Systemd will automatically kill it if you just eval
|
the folder ~/var/www/bantflags/wwwroot/~ to host static content,
|
||||||
~bantflags:main~.
|
or whatever directory is provided to ~wwwroot~.
|
||||||
You will almost certainly have several issues building clsql, the
|
5) If you're hosting on your GNU/Linux distribution of choice, Create a
|
||||||
database connector used. I've [[https://plum.moe/words/bludgeoning-clsql-and-mariadb.html][written a blog post]] on some of the
|
folder called ~keys~ in the same directory as the bantflags
|
||||||
issues I've encountered personally, but there's no guarantee it'll
|
executable.
|
||||||
work. Piece of shit.
|
- E.G. ~/var/www/bantflags/keys/~
|
||||||
|
- 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
|
The backend exposes three endpoints for the userscript to get and post
|
||||||
post flags. Flags themselves are hosted from ~flags/~ which is
|
flags. Flags themselves are hosted from the ~flags/~ directory. This
|
||||||
~www-root/flags/~ from ~config.lisp~ on the filesystem
|
will be whatever value you gave to ~webroot~ (or
|
||||||
|
~/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 |
|
||||||
|
|
||||||
| route | purpse |
|
** Backwards Compatibility
|
||||||
|------------+--------------------------------------------|
|
The API is 1:1 compatable with all previous versions of
|
||||||
| /api/get | Get flags using post numbers in the thread |
|
bantflags. Further improvements are achieved by encoding a ~version~
|
||||||
| /api/post | Add flags to the database |
|
variable when poking endpoints which allows for breaking changes in
|
||||||
| /api/flags | List the flags we support |
|
the script and backend while guaranteeing data can be parsed on both
|
||||||
| /flags/* | The flag images |
|
ends. See [[https://github.com/C-xC-c/BantFlags/tree/master/Docs/][Docs/{endpoint}]] for changes and compatibility.
|
||||||
** 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,36 +0,0 @@
|
|||||||
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,23 +0,0 @@
|
|||||||
;; (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/>
|
|
||||||
|
|
||||||
(asdf:defsystem #:bantflags
|
|
||||||
:description "the bantflags server component"
|
|
||||||
:author "Manx (boku@plum.moe)"
|
|
||||||
:mailto "boku@plum.moe"
|
|
||||||
:license "AGPLv3+"
|
|
||||||
:version "0.0.1"
|
|
||||||
:serial t
|
|
||||||
:depends-on (:hunchentoot
|
|
||||||
:hunchenhelpers
|
|
||||||
:cl-ppcre
|
|
||||||
:clsql
|
|
||||||
:jonathan)
|
|
||||||
:Components
|
|
||||||
((:file "package")
|
|
||||||
(:file "utils")
|
|
||||||
(:file "db")
|
|
||||||
(:file "config")
|
|
||||||
(:file "main")))
|
|
@ -1,14 +0,0 @@
|
|||||||
(in-package #:bantflags)
|
|
||||||
|
|
||||||
(defvar config
|
|
||||||
'((boards ("bant" "uhh"))
|
|
||||||
(staging-password "not implemented")
|
|
||||||
(db-conn ("localhost" "bantflags" "flags" "default"))
|
|
||||||
(poolsize 3)
|
|
||||||
(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,47 +0,0 @@
|
|||||||
;; (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.
|
|
||||||
;; Don't even bother.
|
|
||||||
|
|
||||||
;; We're comparing strings
|
|
||||||
(defparameter *flags* (make-hash-table :test 'equal))
|
|
||||||
(defparameter *boards* (make-hash-table :test 'equal))
|
|
||||||
(defparameter *flags-txt* nil)
|
|
||||||
(defparameter conn nil)
|
|
||||||
|
|
||||||
(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';")
|
|
||||||
|
|
||||||
(defmacro dbfun (name &rest body)
|
|
||||||
`(defun ,name ,(car body)
|
|
||||||
(clsql:with-database (db conn :database-type :mysql :pool t)
|
|
||||||
,@(cdr body))))
|
|
||||||
|
|
||||||
(defun flag-id (flag)
|
|
||||||
(gethash flag *flags*))
|
|
||||||
|
|
||||||
(dbfun insert-post (post_nr board flags)
|
|
||||||
(clsql:execute-command (format nil "insert ignore into posts (post_nr, board) values (~a, '~a');" post_nr board) :database db)
|
|
||||||
(let ((post-id (caar (clsql:query (format nil "select id from posts where post_nr = ~a and board = '~a';" post_nr board) :database db))))
|
|
||||||
(clsql:execute-command
|
|
||||||
(with-output-to-string (s)
|
|
||||||
(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
|
|
||||||
do (format s "(~a,~a)," post-id (flag-id flag)))
|
|
||||||
(format s "(~a,~a);" post-id (flag-id (car (last flags)))))
|
|
||||||
:database db)))
|
|
||||||
|
|
||||||
(dbfun get-posts (posts board)
|
|
||||||
(let ((result (clsql:query (format nil get-posts-sql posts board) :database db))
|
|
||||||
(table (make-hash-table)))
|
|
||||||
(loop for (post_nr . flag) in (reverse result) do
|
|
||||||
(unless (gethash post_nr table)
|
|
||||||
(setf (gethash post_nr table) '()))
|
|
||||||
(push (car flag) (gethash post_nr table)))
|
|
||||||
(jojo:to-json table)))
|
|
||||||
|
|
||||||
(dbfun get-flags ()
|
|
||||||
(clsql:query "select flags.id, flags.flag from flags" :database db))
|
|
@ -1,9 +0,0 @@
|
|||||||
;; 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,53 +0,0 @@
|
|||||||
;; (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 ()
|
|
||||||
(assert (not (null config)))
|
|
||||||
(setf conn (conf 'db-conn))
|
|
||||||
(loop repeat (conf 'poolsize)
|
|
||||||
do ;; This doesn't work lole
|
|
||||||
(clsql:connect conn :database-type :mysql :pool t :if-exists :new))
|
|
||||||
(set-boards)
|
|
||||||
(set-flags)
|
|
||||||
(defvar *serb* (make-instance 'hunchentoot:easy-acceptor
|
|
||||||
:port (conf 'port)
|
|
||||||
:address "127.0.0.1" ;; localhost
|
|
||||||
:document-root (conf 'www-root)
|
|
||||||
:access-log-destination (conf 'access-log)
|
|
||||||
:message-log-destination (conf 'error-log))))
|
|
||||||
|
|
||||||
(defun main ()
|
|
||||||
(handler-case (init)
|
|
||||||
(error (c)
|
|
||||||
(format t "Init fucked up, exiting ~a" c)
|
|
||||||
(return-from main)))
|
|
||||||
(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)
|
|
||||||
(format nil "")) ;; Empty 404 page
|
|
||||||
|
|
||||||
(henh:handle :post (api-post :uri "/api/post") @json
|
|
||||||
(post_nr regions board version)
|
|
||||||
(multiple-value-bind (result msg) (insert-post-p post_nr (cl-ppcre:split "," regions) board)
|
|
||||||
(cond
|
|
||||||
(result
|
|
||||||
(insert-post post_nr board msg)
|
|
||||||
(format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg)) ;; This makes JSON
|
|
||||||
(t (format nil "{\"Error\": \"~a\"}~%" msg)))))
|
|
||||||
|
|
||||||
(henh:handle :post (api-get :uri "/api/get") @json
|
|
||||||
(post_nrs board version)
|
|
||||||
(setf post_nrs (cl-ppcre:split "," post_nrs))
|
|
||||||
(if (get-posts-p post_nrs board)
|
|
||||||
(format nil "~a~%" (get-posts post_nrs board))
|
|
||||||
(t (format nil "{[\"~a\"]}~%" "bad"))))
|
|
||||||
|
|
||||||
(henh:handle :get (api-flags :uri "/api/flags") @plain
|
|
||||||
()
|
|
||||||
(format nil "~a~%" *flags-txt*))
|
|
@ -1,4 +0,0 @@
|
|||||||
(defpackage #:bantflags
|
|
||||||
(:use #:cl)
|
|
||||||
(:export :init
|
|
||||||
:*serb*))
|
|
@ -1,59 +0,0 @@
|
|||||||
;; (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)
|
|
||||||
|
|
||||||
(defvar empty-flag '("empty, or there were errors. Re-set your flags."))
|
|
||||||
|
|
||||||
(defun conf (thing &aux (item (cadr (assoc thing config))))
|
|
||||||
(if (null item)
|
|
||||||
(error "no such config item" thing)
|
|
||||||
item))
|
|
||||||
|
|
||||||
(defun set-boards ()
|
|
||||||
(setf *boards* (make-hash-table :test 'equal))
|
|
||||||
(mapc (lambda (board) (setf (gethash board *boards*) t)) (conf 'boards)))
|
|
||||||
|
|
||||||
(defun set-flags ()
|
|
||||||
(setf *flags* (make-hash-table :test 'equal))
|
|
||||||
(let ((flags (get-flags)))
|
|
||||||
(loop for (id . flag) in flags
|
|
||||||
do (setf (gethash (car flag) *flags*) id))
|
|
||||||
(setf *flags-txt* ;; We don't want users to select `empty-flag`
|
|
||||||
(cl-ppcre:regex-replace (concatenate 'string (car empty-flag) "\\n") ;; newline
|
|
||||||
(format nil "~{~a~^~%~}" (mapcan (lambda (x) (cdr x)) flags))
|
|
||||||
""))))
|
|
||||||
|
|
||||||
;; validation
|
|
||||||
(defun post-number-p (post_nr)
|
|
||||||
(if (or (null post_nr)
|
|
||||||
(null (parse-integer post_nr :junk-allowed t)))
|
|
||||||
nil
|
|
||||||
post_nr))
|
|
||||||
|
|
||||||
(defun boardp (board)
|
|
||||||
(gethash board *boards*))
|
|
||||||
|
|
||||||
(defun insert-post-p (post_nr regions board)
|
|
||||||
(cond
|
|
||||||
((not (post-number-p post_nr))
|
|
||||||
(values nil "Invalid post number."))
|
|
||||||
((not (boardp board))
|
|
||||||
(values nil "Invalid board parameter."))
|
|
||||||
((null regions)
|
|
||||||
(values t empty-flag))
|
|
||||||
((< 30 (length regions))
|
|
||||||
(values nil "Too many flags."))
|
|
||||||
((every (lambda (flag) (gethash flag *flags*)) regions)
|
|
||||||
(values t regions))
|
|
||||||
(t (values t empty-flag))))
|
|
||||||
|
|
||||||
(defun get-posts-p (post_nrs board)
|
|
||||||
(and (not (null post_nrs))
|
|
||||||
(every #'post-number-p post_nrs)
|
|
||||||
(boardp board)))
|
|
||||||
|
|
||||||
;; Content types
|
|
||||||
(defparameter @json "application/json")
|
|
||||||
(defparameter @plain "text/plain")
|
|
Loading…
Reference in new issue