1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-01-23 15:36:52 +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) { Server.prototype.findMatchingRoute = function(request,state) {
for(var t=0; t<this.routes.length; t++) { for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t], var potentialRoute = this.routes[t],
pathRegExp = potentialRoute.path, pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname, pathname = state.urlInfo.pathname,
match; match;
if(state.pathPrefix) { if(state.pathPrefix) {
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) { if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
pathname = pathname.substr(state.pathPrefix.length) || "/"; pathname = pathname.substr(state.pathPrefix.length) || "/";
match = potentialRoute.path.exec(pathname); match = potentialRoute.path.exec(pathname);
} else { } else {
match = false; match = false;
} }
} else { } else {
match = potentialRoute.path.exec(pathname); match = potentialRoute.path.exec(pathname);
} }
// Allow POST as a synonym for PUT because HTML doesn't allow PUT forms // 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"))) { if(match && (
state.params = []; request.method === potentialRoute.method ||
for(var p=1; p<match.length; p++) { (request.method === "POST" && (
state.params.push(match[p]); potentialRoute.method === "PUT" ||
} potentialRoute.method === "DELETE"
return potentialRoute; ))
} )) {
} state.params = [];
return null; for(var p=1; p<match.length; p++) {
state.params.push(match[p]);
}
return potentialRoute;
}
}
return null;
}; };
Server.prototype.methodMappings = { 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.entityName = "bag"
exports.handler = function(request,response,state) { exports.handler = function(request,response,state) {
var server = state.server, if(state.data.bag_name) {
sqlTiddlerDatabase = server.sqlTiddlerDatabase; const result = $tw.mws.store.createBag(state.data.bag_name,state.data.description);
if(!result) {
// Handle DELETE request state.sendResponse(302,{
if(state.data._method === "DELETE") { "Content-Type": "text/plain",
if(state.data.bag_name) { "Location": "/"
const result = $tw.mws.store.deleteBag(state.data.bag_name); });
if(!result) { } else {
state.sendResponse(302,{ state.sendResponse(400,{
"Content-Type": "text/plain", "Content-Type": "text/plain"
"Location": "/" },
}); result.message,
} else { "utf8");
state.sendResponse(400,{ }
"Content-Type": "text/plain" } else {
}, state.sendResponse(400,{
result.message, "Content-Type": "text/plain"
"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"
});
}
}; };
}()); }());

View File

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

View File

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