Skip to content

Commit

Permalink
Merge pull request #376 from akvo/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
wayangalihpratama authored Nov 18, 2024
2 parents 7e88c96 + c1c1193 commit 08fd86e
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 5 deletions.
17 changes: 16 additions & 1 deletion backend/db/crud_case.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from sqlalchemy.orm import Session
from sqlalchemy import and_
from sqlalchemy import and_, cast
from sqlalchemy.dialects.postgresql import TEXT
from typing import Optional, List
from typing_extensions import TypedDict
from fastapi import HTTPException, status
Expand Down Expand Up @@ -95,6 +96,8 @@ def get_all_case(
business_unit_users: Optional[List[int]] = None,
user_cases: Optional[List[int]] = None,
country: Optional[int] = None,
email: Optional[str] = None,
year: Optional[int] = None,
) -> List[CaseListDict]:
case = session.query(Case)
if not show_private:
Expand All @@ -115,6 +118,18 @@ def get_all_case(
case = case.filter(Case.id.in_(user_cases))
if country:
case = case.filter(Case.country == country)
if email:
users = (
session.query(User)
.filter(User.email.ilike("%{}%".format(email.lower().strip())))
.all()
)
user_ids = [u.id for u in users]
case = case.filter(Case.created_by.in_(user_ids))
if year:
case = case.filter(
cast(Case.year, TEXT).ilike("%{}%".format(f"{year}".strip()))
)
count = case.count()
case = case.order_by(Case.id.desc()).offset(skip).limit(limit).all()
return PaginatedCaseData(count=count, data=case)
Expand Down
4 changes: 4 additions & 0 deletions backend/routes/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def get_all_case(
country: Optional[int] = Query(None),
tags: Optional[List[int]] = Query(None),
focus_commodity: Optional[List[int]] = Query(None),
email: Optional[str] = Query(None),
year: Optional[int] = Query(None),
session: Session = Depends(get_session),
credentials: credentials = Depends(security),
):
Expand Down Expand Up @@ -120,6 +122,8 @@ def get_all_case(
user_cases=user_cases,
country=country,
show_private=show_private,
email=email,
year=year,
)
if not cases:
raise HTTPException(status_code=404, detail="Not found")
Expand Down
94 changes: 94 additions & 0 deletions backend/tests/test_023_case_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,97 @@ async def test_get_case_filtered_by_country(
"total": 2,
"total_page": 1,
}

@pytest.mark.asyncio
async def test_get_case_filtered_by_email(
self, app: FastAPI, session: Session, client: AsyncClient
) -> None:
res = await client.get(
app.url_path_for("case:get_all"),
params={"email": "not_found@mail.com"},
headers={"Authorization": f"Bearer {admin_account.token}"},
)
assert res.status_code == 404
res = await client.get(
app.url_path_for("case:get_all"),
params={"email": "admin"},
headers={"Authorization": f"Bearer {admin_account.token}"},
)
assert res.status_code == 200
res = res.json()
assert res == {
"current": 1,
"data": [
{
"id": 2,
"name": "Bali Coffee Production (Private)",
"country": "Bali",
"focus_commodity": 1,
"diversified_commodities_count": 1,
"year": 2023,
"created_at": res["data"][0]["created_at"],
"created_by": "super_admin@akvo.org",
"tags": [],
},
{
"id": 1,
"name": "Bali Rice and Corn Production",
"country": "Bali",
"focus_commodity": 2,
"diversified_commodities_count": 2,
"year": 2023,
"created_at": res["data"][1]["created_at"],
"created_by": "super_admin@akvo.org",
"tags": [2, 1],
},
],
"total": 2,
"total_page": 1,
}

@pytest.mark.asyncio
async def test_get_case_filtered_by_year(
self, app: FastAPI, session: Session, client: AsyncClient
) -> None:
res = await client.get(
app.url_path_for("case:get_all"),
params={"year": "1992"},
headers={"Authorization": f"Bearer {admin_account.token}"},
)
assert res.status_code == 404
res = await client.get(
app.url_path_for("case:get_all"),
params={"year": "2023"},
headers={"Authorization": f"Bearer {admin_account.token}"},
)
assert res.status_code == 200
res = res.json()
assert res == {
"current": 1,
"data": [
{
"id": 2,
"name": "Bali Coffee Production (Private)",
"country": "Bali",
"focus_commodity": 1,
"diversified_commodities_count": 1,
"year": 2023,
"created_at": res["data"][0]["created_at"],
"created_by": "super_admin@akvo.org",
"tags": [],
},
{
"id": 1,
"name": "Bali Rice and Corn Production",
"country": "Bali",
"focus_commodity": 2,
"diversified_commodities_count": 2,
"year": 2023,
"created_at": res["data"][1]["created_at"],
"created_by": "super_admin@akvo.org",
"tags": [2, 1],
},
],
"total": 2,
"total_page": 1,
}
23 changes: 22 additions & 1 deletion frontend/src/components/layout/TableContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,24 @@ const TableContent = ({
buttonProps = {},
paginationProps = {},
otherFilters = null,
showTotalPagination = false,
}) => {
const showTotalOption = showTotalPagination
? {
showTotal: (total) => (
<div
style={{
position: "absolute",
left: 0,
marginLeft: "14px",
}}
>
Total Case: {total}
</div>
),
}
: {};

return (
<Row data-testid="table-content" className="table-content-container">
<Col span={24}>
Expand Down Expand Up @@ -58,7 +75,11 @@ const TableContent = ({
dataSource={dataSource}
columns={columns}
loading={loading}
pagination={{ ...paginationProps, showSizeChanger: false }}
pagination={{
...paginationProps,
...showTotalOption,
showSizeChanger: false,
}}
/>
</Col>
</Row>
Expand Down
46 changes: 43 additions & 3 deletions frontend/src/pages/cases/Cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ import {
} from "@ant-design/icons";
import { api } from "../../lib";
import { UIState, UserState } from "../../store";
import { Select, Space, Button, Row, Col, Popconfirm, message } from "antd";
import {
Select,
Space,
Button,
Row,
Col,
Popconfirm,
message,
Input,
InputNumber,
} from "antd";
import { selectProps, DebounceSelect } from "./components";
import { isEmpty } from "lodash";
import { adminRole } from "../../store/static";
Expand All @@ -25,7 +35,7 @@ const defData = {
};
const filterProps = {
...selectProps,
style: { width: window.innerHeight * 0.225 },
style: { width: window.innerHeight * 0.175 },
};

const Cases = () => {
Expand All @@ -36,6 +46,8 @@ const Cases = () => {
const [country, setCountry] = useState(null);
const [commodity, setCommodity] = useState(null);
const [tags, setTags] = useState([]);
const [email, setEmail] = useState(null);
const [year, setYear] = useState(null);

const tagOptions = UIState.useState((s) => s.tagOptions);
const {
Expand Down Expand Up @@ -79,6 +91,12 @@ const Cases = () => {
const tagQuery = tags.join("&tags=");
url = `${url}&tags=${tagQuery}`;
}
if (email) {
url = `${url}&email=${email}`;
}
if (year) {
url = `${url}&year=${year}`;
}
api
.get(url)
.then((res) => {
Expand All @@ -96,7 +114,17 @@ const Cases = () => {
setRefresh(false);
});
}
}, [currentPage, search, userID, commodity, country, tags, refresh]);
}, [
currentPage,
search,
userID,
commodity,
country,
tags,
refresh,
year,
email,
]);

const fetchUsers = (searchValue) => {
return api
Expand Down Expand Up @@ -318,6 +346,17 @@ const Cases = () => {
value={tags}
onChange={setTags}
/>
<Input
key="4"
placeholder="Case owner email"
onChange={(e) => setEmail(e.target.value)}
/>
<InputNumber
key="5"
placeholder="Year"
controls={false}
onChange={setYear}
/>
</Space>
);

Expand Down Expand Up @@ -356,6 +395,7 @@ const Cases = () => {
onChange: (page) => setCurrentPage(page),
}}
otherFilters={otherFilters}
showTotalPagination={true}
/>
</ContentLayout>
);
Expand Down

0 comments on commit 08fd86e

Please # to comment.