Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement/projects more filter #77

Merged
merged 31 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
036167b
made the main page static and enabled scrolling in the filters component
mtalhabaig3 Jun 21, 2023
88441ea
Solved the height issue of filters menu
mtalhabaig3 Jun 22, 2023
b18a98e
Merge branch 'hotosm:develop' into feature/5844/menu/height
mtalhabaig3 Jun 22, 2023
fde0541
minor changes
mtalhabaig3 Jun 22, 2023
7625f96
added dependency array
mtalhabaig3 Jun 23, 2023
f211ea0
remove the css for hiding scroll bar
mtalhabaig3 Jun 28, 2023
a68367f
Merge branch 'hotosm:develop' into feature/5844/menu/height
mtalhabaig3 Jun 28, 2023
66073a6
Merge branch 'hotosm:develop' into feature/5844/menu/height
mtalhabaig3 Jul 10, 2023
41d270c
Made dropdowns fixed and hide scroll bar
mtalhabaig3 Jul 10, 2023
e2b332a
removed comments
mtalhabaig3 Jul 11, 2023
585d461
Merge branch 'hotosm:develop' into feature/5844/menu/height
mtalhabaig3 Jul 11, 2023
c120198
Merge branch 'hotosm:develop' into feature/5844/menu/height
mtalhabaig3 Aug 17, 2023
8611239
solved the front end test error
mtalhabaig3 Aug 17, 2023
5dc659c
removed comments
mtalhabaig3 Aug 23, 2023
e90fa95
feat: ohsome proxy api for user stats
kaditya97 Mar 22, 2024
83cb4df
Integrate proxy api for ohsomeNow stats
royallsilwallz Mar 26, 2024
b7dc50f
Fix Frontend Test Case failure on CI
royallsilwallz Mar 28, 2024
1282c82
Remove `Footer` in `Live Monitoring View`
royallsilwallz Apr 5, 2024
9afaa69
Merge pull request #6315 from hotosm/feature/liveMonitoringDQ
ramyaragupathy Apr 9, 2024
5826028
Merge pull request #6322 from hotosm/feature/6307-edit-project-button…
ramyaragupathy Apr 9, 2024
cd40d2a
Merge pull request #6323 from hotosm/enhancement/6321-update-social-m…
ramyaragupathy Apr 9, 2024
713027f
Merge pull request #6300 from hotosm/feat/ohsome-api-proxy
ramyaragupathy Apr 9, 2024
7d26e0c
Merge pull request #6312 from hotosm/fix/displaying-images-in-email
ramyaragupathy Apr 9, 2024
0ff9686
Merge branch 'develop' of github.com:hotosm/tasking-manager into enha…
spnayan Apr 10, 2024
67eee80
Prevent api call before filter apply in `Explore Projects` page
spnayan Apr 10, 2024
85dd23a
Fix z-index issue between select dropdown and toggle button in more f…
spnayan Apr 15, 2024
2309994
Increase padding in more filters footer button in more filter
spnayan Apr 15, 2024
d6e009a
Change More Filter to popover layout in laptop screen
spnayan Apr 15, 2024
39744bb
Add overlay on More Filter popover
spnayan Apr 15, 2024
aa3aea4
Close More Filter popover on outside click
spnayan Apr 15, 2024
982528b
Fix test case for More Filters
spnayan Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ def add_api_endpoints(app):
UsersStatisticsAPI,
UsersStatisticsInterestsAPI,
UsersStatisticsAllAPI,
OhsomeProxyAPI,
)

# System API endpoint
Expand Down Expand Up @@ -900,6 +901,9 @@ def add_api_endpoints(app):
UsersStatisticsAllAPI,
format_url("users/statistics/"),
)
api.add_resource(
OhsomeProxyAPI, format_url("users/statistics/ohsome/"), methods=["GET"]
)
# User RecommendedProjects endpoint
api.add_resource(
UsersRecommendedProjectsAPI,
Expand Down
42 changes: 42 additions & 0 deletions backend/api/users/statistics.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from json import JSONEncoder
from datetime import date, timedelta
from flask_restful import Resource, request
import requests

from backend.services.users.user_service import UserService
from backend.services.stats_service import StatsService
from backend.services.interests_service import InterestService
from backend.services.users.authentication_service import token_auth
from backend.api.utils import validate_date_input
from backend.config import EnvironmentConfig


class UsersStatisticsAPI(Resource, JSONEncoder):
Expand Down Expand Up @@ -138,3 +140,43 @@ def get(self):
return stats.to_primitive(), 200
except (KeyError, ValueError) as e:
return {"Error": str(e).split("-")[1], "SubCode": str(e).split("-")[0]}, 400


class OhsomeProxyAPI(Resource):
@token_auth.login_required
def get(self):
"""
Get HomePage Stats
---
tags:
- system
produces:
- application/json
parameters:
- in: header
name: Authorization
description: Base64 encoded session token
required: true
type: string
default: Token sessionTokenHere==
- in: query
name: url
type: string
description: get user stats for osm contributions
responses:
200:
description: User stats
500:
description: Internal Server Error
"""
url = request.args.get("url")
if not url:
return {"Error": "URL is None", "SubCode": "URL not provided"}, 400
try:
headers = {"Authorization": f"Basic {EnvironmentConfig.OHSOME_STATS_TOKEN}"}

# Make the GET request with headers
response = requests.get(url, headers=headers)
return response.json(), 200
except Exception as e:
return {"Error": str(e), "SubCode": "Error fetching data"}, 400
3 changes: 3 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ class EnvironmentConfig:
# Sentry backend DSN
SENTRY_BACKEND_DSN = os.getenv("TM_SENTRY_BACKEND_DSN", None)

# Ohsome Stats Token
OHSOME_STATS_TOKEN = os.getenv("OHSOME_STATS_TOKEN", None)


class TestEnvironmentConfig(EnvironmentConfig):
POSTGRES_TEST_DB = os.getenv("POSTGRES_TEST_DB", None)
Expand Down
31 changes: 30 additions & 1 deletion backend/services/messaging/message_service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re
import time
import datetime
import bleach

from cachetools import TTLCache, cached
from typing import List
Expand Down Expand Up @@ -243,6 +244,34 @@ def send_message_after_comment(
task_link = MessageService.get_task_link(project_id, task_id)
project_link = MessageService.get_project_link(project_id, project_name)

# Clean comment and convert to html
allowed_tags = [
"a",
"b",
"blockquote",
"br",
"code",
"em",
"h1",
"h2",
"h3",
"img",
"i",
"li",
"ol",
"p",
"pre",
"strong",
"ul",
]
allowed_atrributes = {"a": ["href", "rel"], "img": ["src", "alt"]}
clean_comment = bleach.clean(
markdown(comment, output_format="html"),
tags=allowed_tags,
attributes=allowed_atrributes,
) # Bleach input to ensure no nefarious script tags etc
clean_comment = bleach.linkify(clean_comment)

messages = []
for username in usernames:
try:
Expand All @@ -260,7 +289,7 @@ def send_message_after_comment(
f"You were mentioned in a comment in {task_link} "
+ f"of Project {project_link}"
)
message.message = comment
message.message = clean_comment
messages.append(
dict(message=message, user=user, project_name=project_name)
)
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/api/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { remapParamsToAPI } from '../utils/remapParamsToAPI';
import api from './apiClient';
import { UNDERPASS_URL } from '../config';

export const useProjectsQuery = (fullProjectsQuery, action) => {
export const useProjectsQuery = (fullProjectsQuery, action, queryOptions) => {
const token = useSelector((state) => state.auth.token);
const locale = useSelector((state) => state.preferences['locale']);

Expand Down Expand Up @@ -35,6 +35,7 @@ export const useProjectsQuery = (fullProjectsQuery, action) => {
queryKey: ['projects', fullProjectsQuery, action],
queryFn: ({ signal, queryKey }) => fetchProjects(signal, queryKey),
keepPreviousData: true,
...queryOptions,
});
};

Expand Down
15 changes: 10 additions & 5 deletions frontend/src/api/stats.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useQuery } from '@tanstack/react-query';
import { fetchExternalJSONAPI } from '../network/genericJSONRequest';

import { fetchExternalJSONAPI } from '../network/genericJSONRequest';
import api from './apiClient';
import { OHSOME_STATS_BASE_URL } from '../config';

const ohsomeProxyAPI = (url) => {
const token = localStorage.getItem('token');
return api(token).get(`users/statistics/ohsome/?url=${url}`);
};

export const useSystemStatisticsQuery = () => {
const fetchSystemStats = ({ signal }) => {
return api().get(`system/statistics/`, {
Expand Down Expand Up @@ -65,17 +70,17 @@ export const useOsmHashtagStatsQuery = (defaultComment) => {

export const useUserOsmStatsQuery = (id) => {
const fetchUserOsmStats = () => {
return fetchExternalJSONAPI(
return ohsomeProxyAPI(
`${OHSOME_STATS_BASE_URL}/topic/poi,highway,building,waterway/user?userId=${id}`,
true,
);
};

return useQuery({
queryKey: ['user-osm-stats'],
queryFn: fetchUserOsmStats,
useErrorBoundary: true,
select: (data) => data.result,
// userDetail.test.js fails on CI when useErrorBoundary=true
useErrorBoundary: process.env.NODE_ENV !== 'test',
select: (data) => data.data.result,
enabled: !!id,
});
};
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/footer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
import './styles.scss';

const socialNetworks = [
{ link: ORG_TWITTER, icon: <TwitterIcon style={{ height: '20px', width: '20px' }} /> },
{ link: ORG_TWITTER, icon: <TwitterIcon style={{ height: '20px', width: '20px' }} noBg /> },
{ link: ORG_FB, icon: <FacebookIcon style={{ height: '20px', width: '20px' }} /> },
{ link: ORG_YOUTUBE, icon: <YoutubeIcon style={{ height: '20px', width: '20px' }} /> },
{ link: ORG_INSTAGRAM, icon: <InstagramIcon style={{ height: '20px', width: '20px' }} /> },
Expand All @@ -38,6 +38,7 @@ export function Footer() {
'projects/:id/tasks',
'projects/:id/map',
'projects/:id/validate',
'projects/:id/live',
'manage/organisations/new/',
'manage/teams/new',
'manage/campaigns/new',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const Header = () => {
) : null;

return (
<header className="w-100 bb b--grey-light">
<header id="top-header" className="w-100 bb b--grey-light">
<UpdateDialog />
{checkUserEmail()}
{showOrgBar && (
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/projectDetail/shareButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import messages from './messages';
import { ORG_CODE } from '../../config';
import { createPopup } from '../../utils/login';
import { getTwitterLink, getLinkedInLink, getFacebookLink } from '../../utils/shareFunctions';
import { TwitterIconNoBg, FacebookIcon, LinkedinIcon, ShareIcon } from '../svgIcons';
import { TwitterIcon, FacebookIcon, LinkedinIcon, ShareIcon } from '../svgIcons';

export function ShareButton({ projectId }: Object) {
const iconStyle = { width: '1.4em', height: '1.4em' };
Expand Down Expand Up @@ -41,7 +41,7 @@ export function ShareButton({ projectId }: Object) {
className="link no-underline base-font f6 pointer pv1"
onClick={() => twitterPopup(msg)}
>
<TwitterIconNoBg style={iconStyle} className="light-blue v-mid pb1 pr2" />
<TwitterIcon style={iconStyle} className="light-blue v-mid pb1 pr2" />
Tweet
</div>
<div
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/projects/moreFiltersForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const MoreFiltersForm = (props) => {
/>
</fieldset>
)}
<div className="tr w-100 mt3">
<div className="tr w-100 mt3 pb3 ph2">
<Link to="/explore">
<Button className="bg-white blue-dark mr1 f6 pv2">
<FormattedMessage {...messages.clear} />
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/projects/projectNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ export const ProjectNav = (props) => {
setQuery(
{
...fullProjectsQuery,
omitMapResults:!isMapShown
omitMapResults: !isMapShown,
},
'pushIn',
);
// eslint-disable-next-line react-hooks/exhaustive-deps
},[isMapShown])
}, [isMapShown]);
const linkCombo = 'link ph3 f6 pv2 ba b--tan br1 ph3 fw5';

const moreFiltersAnyActive =
Expand All @@ -115,7 +115,7 @@ export const ProjectNav = (props) => {
// onSelectedItemChange={(changes) => console.log(changes)}
return (
/* mb1 mb2-ns (removed for map, but now small gap for more-filters) */
<header className="bt bb b--tan w-100 ">
<header id="explore-nav" className="bt bb b--tan w-100 ">
<div className="mt2 mb1 ph3 dib lh-copy w-100 cf">
<div className="w-80-l w-90-m w-100 fl dib">
<div className="dib">
Expand All @@ -125,6 +125,7 @@ export const ProjectNav = (props) => {
<ProjectsActionFilter setQuery={setQuery} fullProjectsQuery={fullProjectsQuery} />
<Link
to={filterRouteToggled}
id="more-filter-id"
className={`dn mr3 dib-l lh-title f6 ${linkCombo} ${moreFiltersCurrentActiveStyle} blue-dark`}
>
<FormattedMessage {...messages.moreFilters} />
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/svgIcons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export { LoadingIcon } from './loading';
export { EnvelopeIcon } from './envelope';
export { LinkedinIcon } from './linkedin';
export { MarkerIcon } from './marker';
export { TwitterIconNoBg } from './twitterNoBg';
export { ZoomPlusIcon } from './zoomPlus';
export { SidebarIcon } from './sidebar';
export { QuestionCircleIcon } from './questionCircle';
Expand Down
23 changes: 14 additions & 9 deletions frontend/src/components/svgIcons/twitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ import React from 'react';
export class TwitterIcon extends React.PureComponent {
render() {
return (
<svg width="15" height="14" viewBox="0 0 15 14" {...this.props} aria-label="Twitter">
<g fill="none" fillRule="evenodd">
<path d="M-13-13h40v40h-40z" />
<path
d="M12.394 14h-10.5a1.75 1.75 0 0 1-1.75-1.75V1.75C.144.784.928 0 1.894 0h10.5c.966 0 1.75.784 1.75 1.75v10.5a1.75 1.75 0 0 1-1.75 1.75zM5.52 10.556c3.3 0 5.107-2.737 5.107-5.106 0-.078 0-.154-.004-.232.35-.252.655-.57.896-.93a3.637 3.637 0 0 1-1.032.283c.37-.22.654-.574.79-.994a3.57 3.57 0 0 1-1.14.434 1.797 1.797 0 0 0-3.059 1.638 5.096 5.096 0 0 1-3.7-1.876 1.8 1.8 0 0 0 .556 2.398 1.815 1.815 0 0 1-.811-.224v.024c0 .868.619 1.596 1.438 1.76a1.75 1.75 0 0 1-.808.032 1.795 1.795 0 0 0 1.676 1.246 3.6 3.6 0 0 1-2.656.745 5.105 5.105 0 0 0 2.747.802z"
fill="currentColor"
fillRule="nonzero"
/>
</g>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...this.props}
aria-label="Twitter"
>
{!this.props.noBg && <rect width="15" height="15" rx="1" fill="black" />}
<path
d="M8.54822 6.66248L12.644 2H11.6735L8.1156 6.04753L5.27595 2H2L6.29505 8.12111L2 13.01H2.97043L6.72541 8.7347L9.72488 13.01H13.0008L8.54822 6.66248ZM7.21864 8.17485L6.7828 7.56494L3.32038 2.71647H4.81116L7.60626 6.63082L8.04027 7.24073L11.6731 12.3285H10.1823L7.21864 8.17485Z"
fill="white"
/>
</svg>
);
}
Expand Down
14 changes: 0 additions & 14 deletions frontend/src/components/svgIcons/twitterNoBg.js

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/components/taskSelection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export function TaskSelection({ project }: Object) {
)}
<div className="w-100 w-50-ns fl pt3 overflow-y-auto-ns vh-minus-200-ns h-100">
<div className="pl4-l pl2 pr4">
<ProjectHeader project={project} />
<ProjectHeader project={project} showEditLink />
<div className="mt3">
<TabSelector activeSection={activeSection} setActiveSection={setActiveSection} />
<div className="pt3">
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/teamsAndOrgs/featureStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ export const FeatureStats = () => {
const [stats, setStats] = useState({ edits: 0, buildings: 0, roads: 0, pois: 0, waterways: 0 });
const getStats = async () => {
try {
const response = await axios.get(
`${OHSOME_STATS_BASE_URL}/stats/hotosm-project-%2A`,
);
const response = await axios.get(`${OHSOME_STATS_BASE_URL}/stats/hotosm-project-%2A`);
const { edits, buildings, roads } = response.data.result;
setStats({
edits,
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/userDetail/headerProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSelector } from 'react-redux';
import { FormattedMessage, useIntl } from 'react-intl';

import messages from '../user/messages';
import { TwitterIconNoBg, FacebookIcon, LinkedinIcon, ProfilePictureIcon } from '../svgIcons';
import { TwitterIcon, FacebookIcon, LinkedinIcon, ProfilePictureIcon } from '../svgIcons';
import { MappingLevelMessage } from '../mappingLevel';
import { NextMappingLevel } from '../user/topBar';
import { UserOrganisations } from './userTeamsOrgs';
Expand All @@ -26,7 +26,7 @@ export const SocialMedia = ({ data }) => {

switch (field) {
case 'twitterId':
return <TwitterIconNoBg style={iconStyle} className="light-blue v-mid" />;
return <TwitterIcon style={iconStyle} className="light-blue v-mid" />;
case 'facebookId':
return <FacebookIcon style={iconStyle} className="dark-blue v-mid" />;
case 'linkedinId':
Expand Down
1 change: 0 additions & 1 deletion frontend/src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const API_URL = process.env.REACT_APP_API_URL
: 'http://127.0.0.1:5000/api/' + API_VERSION + '/';
export const OHSOME_STATS_BASE_URL =
process.env.REACT_APP_OHSOME_STATS_BASE_URL || 'https://stats.now.ohsome.org/api';
export const OHSOME_STATS_TOKEN = process.env.REACT_APP_OHSOME_STATS_TOKEN || '';

// APPLICATION SETTINGS
export const DEFAULT_LOCALE = process.env.REACT_APP_DEFAULT_LOCALE || 'en';
Expand Down
9 changes: 2 additions & 7 deletions frontend/src/network/genericJSONRequest.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { handleErrors } from '../utils/promise';
import { API_URL, OHSOME_STATS_TOKEN } from '../config';
import { API_URL } from '../config';

export function fetchExternalJSONAPI(url, isSetToken = false): Promise<*> {
export function fetchExternalJSONAPI(url): Promise<*> {
const headers = {
'Content-Type': 'application/json',
};

// Passing token only for ohsomeNow stats
if (isSetToken) {
headers['Authorization'] = `Basic ${OHSOME_STATS_TOKEN}`;
}

return fetch(url, {
method: 'GET',
headers: headers,
Expand Down
Loading
Loading