1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-01-06 15:30:26 +00:00

Refactor DELETE operations into separate handlers AND add POST-to-DELETE mapping to mws-server

This commit is contained in:
Thomas E Tuoti 2024-12-18 10:22:20 -07:00
parent 1d3209e9cf
commit e59eba9086
6 changed files with 178 additions and 132 deletions

View File

@ -317,31 +317,37 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
};
Server.prototype.findMatchingRoute = function(request,state) {
for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t],
pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname,
match;
if(state.pathPrefix) {
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
pathname = pathname.substr(state.pathPrefix.length) || "/";
match = potentialRoute.path.exec(pathname);
} else {
match = false;
}
} else {
match = potentialRoute.path.exec(pathname);
}
// Allow POST as a synonym for PUT because HTML doesn't allow PUT forms
if(match && (request.method === potentialRoute.method || (request.method === "POST" && potentialRoute.method === "PUT"))) {
state.params = [];
for(var p=1; p<match.length; p++) {
state.params.push(match[p]);
}
return potentialRoute;
}
}
return null;
for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t],
pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname,
match;
if(state.pathPrefix) {
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
pathname = pathname.substr(state.pathPrefix.length) || "/";
match = potentialRoute.path.exec(pathname);
} else {
match = false;
}
} else {
match = potentialRoute.path.exec(pathname);
}
// Allow POST as a synonym for PUT and DELETE because HTML doesn't allow these methods in forms
if(match && (
request.method === potentialRoute.method ||
(request.method === "POST" && (
potentialRoute.method === "PUT" ||
potentialRoute.method === "DELETE"
))
)) {
state.params = [];
for(var p=1; p<match.length; p++) {
state.params.push(match[p]);
}
return potentialRoute;
}
}
return null;
};
Server.prototype.methodMappings = {

View File

@ -0,0 +1,48 @@
/*\
title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/delete-bag.js
type: application/javascript
module-type: mws-route
DELETE /bags/:bag-name
\*/
(function() {
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.method = "DELETE";
exports.path = /^\/bags\/([^\/]+)$/;
exports.csrfDisable = true;
exports.useACL = true;
exports.entityName = "bag"
exports.handler = function(request,response,state) {
const bagName = state.params[0];
if(bagName) {
const result = $tw.mws.store.deleteBag(bagName);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
};
}());

View File

@ -0,0 +1,48 @@
/*\
title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/delete-recipe.js
type: application/javascript
module-type: mws-route
DELETE /recipes/:recipe-name
\*/
(function() {
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.method = "DELETE";
exports.path = /^\/recipes\/([^\/]+)$/;
exports.csrfDisable = true;
exports.useACL = true;
exports.entityName = "recipe"
exports.handler = function(request,response,state) {
const recipeName = state.params[0];
if(recipeName) {
const result = $tw.mws.store.deleteRecipe(recipeName);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
};
}());

View File

@ -30,52 +30,25 @@ exports.useACL = true;
exports.entityName = "bag"
exports.handler = function(request,response,state) {
var server = state.server,
sqlTiddlerDatabase = server.sqlTiddlerDatabase;
// Handle DELETE request
if(state.data._method === "DELETE") {
if(state.data.bag_name) {
const result = $tw.mws.store.deleteBag(state.data.bag_name);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
return;
}
if(state.data.bag_name) {
const result = $tw.mws.store.createBag(state.data.bag_name,state.data.description);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
if(state.data.bag_name) {
const result = $tw.mws.store.createBag(state.data.bag_name,state.data.description);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
};
}());
}());

View File

@ -4,7 +4,6 @@ type: application/javascript
module-type: mws-route
POST /recipes
DELETE /recipes (via _method=DELETE)
Parameters:
recipe_name
@ -31,56 +30,31 @@ exports.useACL = true;
exports.entityName = "recipe"
exports.handler = function(request,response,state) {
var server = state.server,
sqlTiddlerDatabase = server.sqlTiddlerDatabase;
// Check and handle if this is a DELETE request
if(state.data._method === "DELETE") {
if(state.data.recipe_name && state.data.bag_names) {
const result = sqlTiddlerDatabase.deleteRecipe(state.data.recipe_name);
if(!result) {
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
return;
}
// Handle POST request (original code)
if(state.data.recipe_name && state.data.bag_names) {
const result = $tw.mws.store.createRecipe(state.data.recipe_name,$tw.utils.parseStringArray(state.data.bag_names),state.data.description);
if(!result) {
if(state.authenticatedUser) {
sqlTiddlerDatabase.assignRecipeToUser(state.data.recipe_name,state.authenticatedUser.user_id);
}
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
var server = state.server,
sqlTiddlerDatabase = server.sqlTiddlerDatabase;
if(state.data.recipe_name && state.data.bag_names) {
const result = $tw.mws.store.createRecipe(state.data.recipe_name,$tw.utils.parseStringArray(state.data.bag_names),state.data.description);
if(!result) {
if(state.authenticatedUser) {
sqlTiddlerDatabase.assignRecipeToUser(state.data.recipe_name,state.authenticatedUser.user_id);
}
state.sendResponse(302,{
"Content-Type": "text/plain",
"Location": "/"
});
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
},
result.message,
"utf8");
}
} else {
state.sendResponse(400,{
"Content-Type": "text/plain"
});
}
};
}());

View File

@ -88,10 +88,8 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
<$text text={{{ [<recipe-info>jsonget[description]] }}}/>
</div>
<div class="mws-wiki-card-actions">
<form action="/recipes" method="post">
<form action={{{ [<recipe-info>jsonget[recipe_name]addprefix[/recipes/]] }}} method="post" onsubmit="return confirmRecipeDelete(this)">
<input type="hidden" name="_method" value="DELETE"/>
<input type="hidden" name="recipe_name" value={{{ [<recipe-info>jsonget[recipe_name]] }}}/>
<input type="hidden" name="bag_names" value={{{ [<recipe-info>jsonget[bag_names]join[ ]] }}}/>
<button type="submit" class="mws-delete-button">Delete Recipe</button>
</form>
</div>
@ -142,12 +140,11 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
<$transclude $variable="bagPill"/>
<$text text={{{ [<bag-info>jsonget[description]] }}}/>
<div class="mws-wiki-card-actions">
<form action="/bags" method="post" onsubmit="return confirmBagDelete(this)">
<input type="hidden" name="_method" value="DELETE"/>
<input type="hidden" name="bag_name" value={{{ [<bag-info>jsonget[bag_name]] }}}/>
<button type="submit" class="mws-delete-button">Delete Bag</button>
</form>
</div>
<form action={{{ [<bag-info>jsonget[bag_name]addprefix[/bags/]] }}} method="post" onsubmit="return confirmBagDelete(this)">
<input type="hidden" name="_method" value="DELETE"/>
<button type="submit" class="mws-delete-button">Delete Bag</button>
</form>
</div>
</$let>
</li>
</$list>