Skip to content

Commit

Permalink
Merge pull request #1168 from hotosm/feat/frontend-delete-proj
Browse files Browse the repository at this point in the history
Project deletion via frontend
  • Loading branch information
varun2948 authored Feb 6, 2024
2 parents 1007392 + 81cd778 commit c8bd552
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 4 deletions.
6 changes: 4 additions & 2 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,21 @@ git checkout main

These steps are essential to run and test your code!

#### 1. Setup OSM OAUTH 2.0
#### 1. Setup OSM OAuth 2.0

The FMTM uses OAUTH2 with OSM to authenticate users.
The FMTM uses OAuth with OSM to authenticate users.

To properly configure your FMTM project, you will need to create keys for OSM.

1. [Login to OSM][28]
(_If you do not have an account yet, click the signup
button at the top navigation bar to create one_).

Click the drop down arrow on the top right of the navigation bar
and select My Settings.

2. Register your FMTM instance to OAuth 2 applications.

Put your login redirect url as `http://127.0.0.1:7051/osmauth/` if running locally,
or for production replace with https://{YOUR_DOMAIN}/osmauth/

Expand Down
3 changes: 2 additions & 1 deletion src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from sqlalchemy.sql import text

from app.auth.osm import AuthUser, login_required
from app.auth.roles import org_admin
from app.central import central_crud
from app.db import database, db_models
from app.models.enums import TILES_FORMATS, TILES_SOURCE, HTTPStatus
Expand Down Expand Up @@ -215,7 +216,7 @@ async def read_project(project_id: int, db: Session = Depends(database.get_db)):
@router.delete("/{project_id}")
async def delete_project(
project: db_models.DbProject = Depends(project_deps.get_project_by_id),
current_user: AuthUser = Depends(login_required),
current_user: AuthUser = Depends(org_admin),
db: Session = Depends(database.get_db),
):
"""Delete a project from both ODK Central and the local database."""
Expand Down
42 changes: 42 additions & 0 deletions src/frontend/src/api/CreateProjectService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from 'axios';
import { API } from '@/api';
import { CreateProjectActions } from '@/store/slices/CreateProjectSlice';
import {
ProjectDetailsModel,
Expand Down Expand Up @@ -519,6 +520,46 @@ const ValidateCustomForm: Function = (url: string, formUpload: any) => {
await validateCustomForm(url, formUpload);
};
};

const DeleteProjectService: Function = (url: string) => {
return async (dispatch) => {
const deleteProject = async (url: string) => {
try {
await API.delete(url);
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Project deleted. Redirecting...',
variant: 'success',
duration: 2000,
}),
);
// Redirect to homepage
setTimeout(() => {
window.location.href = '/';
}, 2000);
} catch (error) {
if (error.response.status === 404) {
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Project already deleted',
variant: 'success',
duration: 2000,
}),
);
} else {
console.log(error);
console.log('Project deletion failed.');
}
}
};

await deleteProject(url);
// TODO extra cleanup required?
};
};

export {
UploadAreaService,
CreateProjectService,
Expand All @@ -534,4 +575,5 @@ export {
PostFormUpdate,
EditProjectBoundaryService,
ValidateCustomForm,
DeleteProjectService,
};
2 changes: 1 addition & 1 deletion src/frontend/src/components/MapDescriptionComponents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CoreModules from '@/shared/CoreModules';
const MapDescriptionComponents = ({ type, state, defaultTheme }) => {
const descriptionData = [
{
value: 'Descriptions',
value: 'Description',
element: <CoreModules.Typography align="center">{state.projectInfo.description}</CoreModules.Typography>,
},
// {
Expand Down
36 changes: 36 additions & 0 deletions src/frontend/src/components/editproject/DeleteProject.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import CoreModules from '@/shared/CoreModules';
import { DeleteProjectService } from '@/api/CreateProjectService';

const DeleteProject = ({ projectId }) => {
const dispatch = CoreModules.useAppDispatch();

const handleSubmit = (e) => {
e.preventDefault();
dispatch(DeleteProjectService(`/projects/${projectId}`));
};

return (
<form onSubmit={handleSubmit}>
<CoreModules.Stack flexDirection="row">
<CoreModules.Stack sx={{ width: '45%' }}>
<CoreModules.Stack sx={{ display: 'flex', justifyContent: 'flex-end', mt: 4 }}>
<CoreModules.LoadingButton
// disabled={updateBoundaryLoading}
type="submit"
// loading={updateBoundaryLoading}
loadingPosition="end"
// endIcon={<AssetModules.SettingsSuggestIcon />}
variant="contained"
color="error"
>
Delete
</CoreModules.LoadingButton>
</CoreModules.Stack>
</CoreModules.Stack>
</CoreModules.Stack>
</form>
);
};

export default DeleteProject;
5 changes: 5 additions & 0 deletions src/frontend/src/constants/EditProjectSidebarContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const SidebarContent: ISidebarContent[] = [
name: 'Update Project Boundary',
slug: 'update-project-boundary',
},
{
id: 4,
name: 'Delete Project',
slug: 'delete-project',
},
];

export default SidebarContent;
12 changes: 12 additions & 0 deletions src/frontend/src/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,18 @@ const routes = createBrowserRouter([
</ProtectedRoute>
),
},
{
path: 'edit-project/delete/:projectId',
element: (
<ProtectedRoute>
<Suspense fallback={<div>Loading...</div>}>
<ErrorBoundary>
<EditProject />
</ErrorBoundary>
</Suspense>
</ProtectedRoute>
),
},
{
path: '/osmauth/',
element: (
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/src/views/EditProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SidebarContent from '@/constants/EditProjectSidebarContent';
import { useNavigate } from 'react-router-dom';
import UpdateForm from '@/components/editproject/UpdateForm';
import UpdateProjectArea from '@/components/editproject/UpdateProjectArea';
import DeleteProject from '@/components/editproject/DeleteProject';

const EditProject: React.FC = () => {
const dispatch = CoreModules.useAppDispatch();
Expand Down Expand Up @@ -86,6 +87,7 @@ const EditProject: React.FC = () => {
{selectedTab === 'project-description' ? <EditProjectDetails projectId={decodedProjectId} /> : null}
{selectedTab === 'form-update' ? <UpdateForm projectId={decodedProjectId} /> : null}
{selectedTab === 'update-project-boundary' ? <UpdateProjectArea projectId={decodedProjectId} /> : null}
{selectedTab === 'delete-project' ? <DeleteProject projectId={decodedProjectId} /> : null}
</CoreModules.Stack>
</CoreModules.Stack>
</CoreModules.Stack>
Expand Down

0 comments on commit c8bd552

Please sign in to comment.