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
|
||||
|
||||
# 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
|
||||
\#*#
|
||||
backups/
|
||||
|
@ -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
|
||||
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]].
|
||||
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]].
|
||||
|
||||
[[https://flags.plum.moe/bantflags.user.js][Install bantflags]]
|
||||
[[https://flags.plum.moe/bantflags.user.js][Install bantflags]]
|
||||
|
||||
** Userscript
|
||||
The userscript uses of ~GM_xmlhttpRequest~ to get and post flags with
|
||||
the backend . A user's flags are stored between pages using
|
||||
~GM_setValue~ and ~GM_getValue~.
|
||||
The userscript uses of ~GM_xmlhttpRequest~ to get and post flags
|
||||
with the backend . A user's flags are stored between pages using
|
||||
~GM_setValue~ and ~GM_getValue~, or their GreaseMonkey4
|
||||
equivalents.
|
||||
|
||||
Old versions of GreaseMonkey will be able to recieve updates to the
|
||||
script through the ~@updateURL~ and ~@downloadURL~ directives, though
|
||||
these were depricated sometime in GreaseMonkey 3.x and updates are
|
||||
only checked from the location the script was downloaded from so be
|
||||
careful where you upload links.
|
||||
Old versions of GreaseMonkey will be able to recieve updates to the
|
||||
script through the ~@updateURL~ and ~@downloadURL~ directives,
|
||||
though these were depricated sometime in GreaseMonkey 3.x and
|
||||
updates are only checked from the location the script was
|
||||
downloaded from so be careful where you upload links.
|
||||
|
||||
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
|
||||
example nginx config.
|
||||
On self hosting, changing ~back_end~ to your domain /should/ be all
|
||||
you need to do, but don't take this as fact.
|
||||
|
||||
The userscript has been designed specifically to target ECMAScript
|
||||
2015 (ES6), making liberal use of arrow functions, and const/let
|
||||
declarations. Update your hecking browser.
|
||||
The userscript has been designed specifically to target ECMAScript
|
||||
2015 (ES6), making liberal use of arrow functions, and const/let
|
||||
declarations. Update your hecking browser.
|
||||
|
||||
** Backend
|
||||
*** Prerequisites
|
||||
- .NET Core 3.1
|
||||
- MariaDB / MySQL
|
||||
|
||||
*** .NET dependancies
|
||||
- Nito.AsyncEX
|
||||
- Newtonsoft.Json
|
||||
- MySql.Data
|
||||
- Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
||||
- Microsoft.AspNetCore.StaticFiles
|
||||
- Microsoft.AspNetCore.Razor
|
||||
- Microsoft.EntityFrameworkCore.SqlServer
|
||||
- Microsoft.EntityFrameworkCore.Tools
|
||||
- Magick.NET-Q8-AnyCPU
|
||||
|
||||
- I use SBCL
|
||||
- Some mysql, I use Mariadb
|
||||
- Quicklisp
|
||||
*** Dependancies
|
||||
- hunchentoot
|
||||
- [[https://github.com/C-xC-c/hunchenhelpers][hunchenhelpers]], my hunchentoot helper library (yes I'm proud of
|
||||
the name)
|
||||
- clsql
|
||||
- jonathan, the JSON encoder/decoder
|
||||
- cl-ppcre
|
||||
*** Setup
|
||||
1) [[https://dotnet.microsoft.com/download/dotnet-core][Install .NET Core]]
|
||||
2) Clone and build the BantFlags solution.
|
||||
3) Create the database using [[https://github.com/C-xC-c/BantFlags/blob/master/Environment/database.sql][database.sql]].
|
||||
- *Change the password*.
|
||||
4) configure ~BantFlags/appsettings.example.json~ with your connection
|
||||
string and webroot (where you'll serve the flags from *without a
|
||||
trailing slash*) and rename it to ~appsettings.json~
|
||||
- [[./BantFlags/appsettings.example.json][example appsettings.json]]
|
||||
- ASP.NET Core applications look for a folder called ~wwwroot~ in
|
||||
the same directory as the application for static files. However
|
||||
you can choose to logically seperate these by providing a vaild
|
||||
directory to ~webroot~.
|
||||
- That is to say, if the bantflags application is in
|
||||
~/var/www/bantflags/BantFlags.dll~, the program will look for
|
||||
the folder ~/var/www/bantflags/wwwroot/~ to host static content,
|
||||
or whatever directory is provided to ~wwwroot~.
|
||||
5) If you're hosting on your GNU/Linux distribution of choice, Create a
|
||||
folder called ~keys~ in the same directory as the bantflags
|
||||
executable.
|
||||
- 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.
|
||||
|
||||
1. clone the project
|
||||
2. Symlink src/ to your ~/quicklisp/local-projects
|
||||
3. Move ~src/config.example.org~ to ~src/config.org~ and change it
|
||||
to whatever your settings are.
|
||||
4. Initialise the database by doing something like ~mysql <<
|
||||
env/database.sql~, This will create all the tables you will
|
||||
need, plus an entry for the ~`empty flag`~
|
||||
5. Type the following into your repl:
|
||||
#+BEGIN_SRC lisp
|
||||
(ql:quickload :bantflags)
|
||||
(bantflags:main)
|
||||
#+END_SRC
|
||||
6. To use bantflags as a Systemd service, I have included an
|
||||
example service and an ~init.el~ file for the service to run,
|
||||
since Systemd will automatically kill it if you just eval
|
||||
~bantflags:main~.
|
||||
You will almost certainly have several issues building clsql, the
|
||||
database connector used. I've [[https://plum.moe/words/bludgeoning-clsql-and-mariadb.html][written a blog post]] on some of the
|
||||
issues I've encountered personally, but there's no guarantee it'll
|
||||
work. Piece of shit.
|
||||
*** Database
|
||||
Tables look like this:
|
||||
Tables look like this:
|
||||
|
||||
*posts*
|
||||
| id | post_nr | board |
|
||||
| 1 | 12345 | bant |
|
||||
| 2 | 56789 | bant |
|
||||
*flags*
|
||||
| id | flag |
|
||||
| 1 | patchouli |
|
||||
| 2 | chen |
|
||||
*postflags*
|
||||
| id | post_nr | flag |
|
||||
| 1 | 1 | 1 |
|
||||
| 2 | 1 | 2 |
|
||||
| 2 | 2 | 2 |
|
||||
where ~post_nr~ and ~flag~ in *postflags* are the id fields in their
|
||||
respective tables.
|
||||
*posts*
|
||||
| id | post_nr | board |
|
||||
| 1 | 12345 | bant |
|
||||
| 2 | 56789 | bant |
|
||||
*flags*
|
||||
| id | flag |
|
||||
| 1 | patchouli |
|
||||
| 2 | chen |
|
||||
*postflags*
|
||||
| id | post_nr | flag |
|
||||
| 1 | 1 | 1 |
|
||||
| 2 | 1 | 2 |
|
||||
| 2 | 2 | 2 |
|
||||
where ~post_nr~ and ~flag~ in *postflags* are the id fields in their
|
||||
respective tables.
|
||||
*** API
|
||||
The backend exposes three endpoints for the userscript to get and post
|
||||
flags. Flags themselves are hosted from the ~flags/~ directory. This
|
||||
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 |
|
||||
The backend exposes three endpoints for the userscript to get and
|
||||
post flags. Flags themselves are hosted from ~flags/~ which is
|
||||
~www-root/flags/~ from ~config.lisp~ on the filesystem
|
||||
|
||||
** Backwards Compatibility
|
||||
The API is 1:1 compatable with all previous versions of
|
||||
bantflags. Further improvements are achieved by encoding a ~version~
|
||||
variable when poking endpoints which allows for breaking changes in
|
||||
the script and backend while guaranteeing data can be parsed on both
|
||||
ends. See [[https://github.com/C-xC-c/BantFlags/tree/master/Docs/][Docs/{endpoint}]] for changes and compatibility.
|
||||
| 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 |
|
||||
** 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]
|
||||
Description=bantflags backend
|
||||
Description=bantflags serb
|
||||
|
||||
[Service]
|
||||
# Set to the location of the application
|
||||
WorkingDirectory=/etc/bantflags
|
||||
ExecStart=/usr/bin/dotnet /etc/bantflags/BantFlags.dll
|
||||
WorkingDirectory=/var/www/bantflags/src/
|
||||
ExecStart=/usr/bin/env sbcl --load init.el
|
||||
Restart=always
|
||||
# restarts 10 seconds after it goes bang
|
||||
RestartSec=10
|
||||
KillSignal=SIGINT
|
||||
SyslogIdentifier=bantflags
|
||||
User=www-data
|
||||
User=nginx
|
||||
|
||||
[Install]
|
||||
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
|
||||
'((boards "bant")
|
||||
'((boards ("bant" "uhh"))
|
||||
(staging-password "not implemented")
|
||||
(db-conn "bantflags" "flags" "default")
|
||||
(db-conn ("localhost" "bantflags" "flags" "default"))
|
||||
(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.
|
||||
;; Don't even bother.
|
||||
|
||||
;; Comparing strings with both
|
||||
;; We're comparing strings
|
||||
(defparameter *flags* (make-hash-table :test 'equal))
|
||||
(defparameter *boards* (make-hash-table :test 'equal))
|
||||
(defparameter *flags-txt* nil)
|
||||
(defparameter conn-str 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';")
|
||||
(defparameter conn nil)
|
||||
|
||||
(defun fuck-you-fukamachi (conn |;_;|)
|
||||
"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 |;_;|)))))
|
||||
(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)
|
||||
(dbi:with-connection (conn :mysql
|
||||
:database-name (car conn-str)
|
||||
:username (nth 1 conn-str)
|
||||
:password (nth 2 conn-str))
|
||||
(dbi:do-sql conn "set names 'utf8';") ;; I fucking hate computers
|
||||
,@(cdr body))))
|
||||
(clsql:with-database (db conn :database-type :mysql :pool t)
|
||||
,@(cdr body))))
|
||||
|
||||
(defun flag-id (flag)
|
||||
(gethash flag *flags*))
|
||||
|
||||
(dbfun ping ()
|
||||
(dbi:ping conn))
|
||||
|
||||
(dbfun insert-post (post_nr board flags)
|
||||
(dbi:do-sql conn
|
||||
(format nil "insert ignore into posts (post_nr, board) values (~a, '~a');" post_nr board))
|
||||
(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)))))))
|
||||
(dbi:do-sql conn
|
||||
(with-output-to-string (s)
|
||||
(format s "insert into postflags (post_nr, flag) values")
|
||||
(loop for flag in (butlast flags)
|
||||
do (format s "(~a,~a)," post-id (flag-id flag)))
|
||||
(format s "(~a,~a);" post-id (flag-id (car (last 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 (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)))
|
||||
(loop for (post_nr . flag) in result do
|
||||
(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 ()
|
||||
(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 ()
|
||||
(set-db-conn)
|
||||
(dotimes (_ (cconf 'poolsize))
|
||||
(dbi:connect-cached :mysql
|
||||
:database-name (car conn-str)
|
||||
:username (nth 1 conn-str)
|
||||
:password (nth 2 conn-str)))
|
||||
(ping) ;; test db conn
|
||||
(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 4242
|
||||
:document-root (cconf 'www-root)))
|
||||
(hunchentoot:start +serb+))
|
||||
(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)))
|
||||
(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)
|
||||
(format nil ""))
|
||||
|
||||
(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))
|
||||
(format nil "")) ;; Empty 404 page
|
||||
|
||||
(handle :post (api-post :uri "/api/post")
|
||||
(henh:handle :post (api-post :uri "/api/post") @json
|
||||
(post_nr regions board version)
|
||||
(setf (hunchentoot:content-type*) "application/json")
|
||||
(let ((separator (if (< 1 (get-version version)) "," "||")))
|
||||
(multiple-value-bind (result msg) (post-valid-p post_nr regions board separator)
|
||||
(cond
|
||||
(result
|
||||
(insert-post post_nr board msg)
|
||||
(format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg))
|
||||
(t
|
||||
(format nil "{\"Error\": \"~a\"}~%" msg))))))
|
||||
(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)))))
|
||||
|
||||
(handle :post (api-get :uri "/api/get")
|
||||
(henh:handle :post (api-get :uri "/api/get") @json
|
||||
(post_nrs board version)
|
||||
(@json tbnl:*reply*)
|
||||
(setf post_nrs (str:split "," post_nrs))
|
||||
(cond
|
||||
((and (loop for x in post_nrs always (post-number-p x))
|
||||
(boardp board))
|
||||
(format nil "~a~%" (get-posts post_nrs board)))
|
||||
(t (format nil "~a~%" "bad"))))
|
||||
(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"))))
|
||||
|
||||
(handle :get (api-flags :uri "/api/flags")
|
||||
(henh:handle :get (api-flags :uri "/api/flags") @plain
|
||||
()
|
||||
(@plain tbnl:*reply*)
|
||||
(format nil "~a~%" *flags-txt*))
|
||||
|
@ -0,0 +1,4 @@
|
||||
(defpackage #:bantflags
|
||||
(:use #:cl)
|
||||
(:export :init
|
||||
:*serb*))
|
Loading…
Reference in new issue