mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-01-23 23:46:52 +00:00
MWS - added DELETE functionality to both Recipes and Bags
This commit is contained in:
parent
060bea89ae
commit
1758a9ce12
@ -30,6 +30,33 @@ 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) {
|
||||
@ -52,3 +79,4 @@ exports.handler = function(request,response,state) {
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -4,9 +4,9 @@ type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
POST /recipes
|
||||
DELETE /recipes (via _method=DELETE)
|
||||
|
||||
Parameters:
|
||||
|
||||
recipe_name
|
||||
description
|
||||
bag_names: space separated list of bags
|
||||
@ -32,7 +32,33 @@ exports.entityName = "recipe"
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var server = state.server,
|
||||
sqlTiddlerDatabase = server.sqlTiddlerDatabase
|
||||
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) {
|
||||
|
@ -203,6 +203,31 @@ SqlTiddlerDatabase.prototype.listBags = function() {
|
||||
return rows;
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a recipe and its bag associations
|
||||
*/
|
||||
SqlTiddlerDatabase.prototype.deleteRecipe = function(recipe_name) {
|
||||
// Delete recipe_bags entries first (due to foreign key constraints)
|
||||
this.engine.runStatement(`
|
||||
DELETE FROM recipe_bags
|
||||
WHERE recipe_id = (
|
||||
SELECT recipe_id
|
||||
FROM recipes
|
||||
WHERE recipe_name = $recipe_name
|
||||
)
|
||||
`, {
|
||||
$recipe_name: recipe_name
|
||||
});
|
||||
|
||||
// Then delete the recipe itself
|
||||
this.engine.runStatement(`
|
||||
DELETE FROM recipes
|
||||
WHERE recipe_name = $recipe_name
|
||||
`, {
|
||||
$recipe_name: recipe_name
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Create or update a bag
|
||||
Returns the bag_id of the bag
|
||||
@ -229,6 +254,19 @@ SqlTiddlerDatabase.prototype.createBag = function(bag_name,description,accesscon
|
||||
return updateBags.lastInsertRowid;
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a bag and all its associated data
|
||||
*/
|
||||
SqlTiddlerDatabase.prototype.deleteBag = function(bag_name) {
|
||||
// Delete the bag (cascade will handle related records)
|
||||
this.engine.runStatement(`
|
||||
DELETE FROM bags
|
||||
WHERE bag_name = $bag_name
|
||||
`, {
|
||||
$bag_name: bag_name
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Returns array of {recipe_name:,recipe_id:,description:,bag_names: []}
|
||||
*/
|
||||
@ -1446,3 +1484,4 @@ SqlTiddlerDatabase.prototype.getRoleById = function(roleId) {
|
||||
exports.SqlTiddlerDatabase = SqlTiddlerDatabase;
|
||||
|
||||
})();
|
||||
|
@ -95,6 +95,46 @@ SqlTiddlerStore.prototype.validateItemName = function(name,allowPrivilegedCharac
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a recipe. Returns null on success, or {message:} on error
|
||||
*/
|
||||
SqlTiddlerStore.prototype.deleteRecipe = function(recipe_name) {
|
||||
var self = this;
|
||||
return this.sqlTiddlerDatabase.transaction(function() {
|
||||
// Check if recipe exists
|
||||
const recipes = self.sqlTiddlerDatabase.listRecipes();
|
||||
const recipeExists = recipes.some(recipe => recipe.recipe_name === recipe_name);
|
||||
if(!recipeExists) {
|
||||
return {message: "Recipe does not exist"};
|
||||
}
|
||||
|
||||
// Delete the recipe
|
||||
self.sqlTiddlerDatabase.deleteRecipe(recipe_name);
|
||||
self.dispatchEvent("change");
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a bag. Returns null on success, or {message:} on error
|
||||
*/
|
||||
SqlTiddlerStore.prototype.deleteBag = function(bag_name) {
|
||||
var self = this;
|
||||
return this.sqlTiddlerDatabase.transaction(function() {
|
||||
// Check if bag exists
|
||||
const bags = self.sqlTiddlerDatabase.listBags();
|
||||
const bagExists = bags.some(bag => bag.bag_name === bag_name);
|
||||
if(!bagExists) {
|
||||
return {message: "Bag does not exist"};
|
||||
}
|
||||
|
||||
// Delete the bag
|
||||
self.sqlTiddlerDatabase.deleteBag(bag_name);
|
||||
self.dispatchEvent("change");
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Returns null if the argument is an array of valid bag/recipe names, or a string error message if not
|
||||
*/
|
||||
|
@ -86,6 +86,14 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
|
||||
</div>
|
||||
<div class="mws-wiki-card-description">
|
||||
<$text text={{{ [<recipe-info>jsonget[description]] }}}/>
|
||||
</div>
|
||||
<div class="mws-wiki-card-actions">
|
||||
<form action="/recipes" method="post">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@ -133,6 +141,13 @@ 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>
|
||||
</$let>
|
||||
</li>
|
||||
</$list>
|
||||
@ -241,6 +256,27 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mws-delete-button {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.mws-delete-button:hover {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
|
||||
.mws-wiki-card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.mws-admin-dropdown-content a:hover {background-color: #ddd;}
|
||||
|
||||
.mws-admin-dropdown:hover .mws-admin-dropdown-content {display: block;}
|
||||
|
Loading…
Reference in New Issue
Block a user