diff --git a/backend/apps/ifc_validation_bff/urls.py b/backend/apps/ifc_validation_bff/urls.py index cc30b428..8c4e5563 100644 --- a/backend/apps/ifc_validation_bff/urls.py +++ b/backend/apps/ifc_validation_bff/urls.py @@ -1,12 +1,13 @@ from django.urls import path -from .views_legacy import me, models_paginated, upload, delete +from .views_legacy import me, logout_view, models_paginated, upload, delete from .views_legacy import report, report_error urlpatterns = [ # 'Flask'-way of doing things; backend for legacy API (< 0.6) path('api/me', me), + path('api/logout', logout_view), path('api/models_paginated//', models_paginated), path('api/', upload), path('api/delete/', delete), diff --git a/backend/apps/ifc_validation_bff/views_legacy.py b/backend/apps/ifc_validation_bff/views_legacy.py index 918504e7..418a2cbb 100644 --- a/backend/apps/ifc_validation_bff/views_legacy.py +++ b/backend/apps/ifc_validation_bff/views_legacy.py @@ -90,21 +90,9 @@ def get_current_user(request): def create_redirect_response(login=True, dashboard=False): - - if dashboard: - - return JsonResponse({ - "redirect": '/dashboard', - "reason": "403 - Forbidden" - }) - - else: - - return JsonResponse({ - "redirect": LOGIN_URL, - "reason": "401 - Unauthorized" - }) - + return JsonResponse({ + "redirect": LOGIN_URL if login else '/dashboard', + }) @functools.lru_cache(maxsize=1024) def get_feature_filename(feature_code): @@ -249,6 +237,15 @@ def me(request): return create_redirect_response(login=True) +@ensure_csrf_cookie +@csrf_protect +def logout_view(request): + if get_current_user(request): + request.session.pop('user', None) + + return create_redirect_response(login=True) + + @ensure_csrf_cookie def models_paginated(request, start: int, end: int): @@ -287,7 +284,7 @@ def upload(request): if not user: return create_redirect_response(login=True) if not user.is_active: - return create_redirect_response(waiting_zone=True) + return create_redirect_response(dashboard=True) set_user_context(user) diff --git a/frontend/src/App.js b/frontend/src/App.js index 2d3dfde1..bd5b76d2 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,4 @@ -import { Typography } from '@mui/material'; +import { Link, Typography } from '@mui/material'; import Dz from './Dz' import ResponsiveAppBar from './ResponsiveAppBar' @@ -6,8 +6,11 @@ import Disclaimer from './Disclaimer'; import Footer from './Footer' import Grid from '@mui/material/Grid'; import Box from '@mui/material/Box'; +import Paper from '@mui/material/Paper'; import SideMenu from './SideMenu'; import VerticalLinearStepper from './VerticalLinearStepper' +import Container from '@mui/material/Container'; +import Stack from '@mui/material/Stack'; import FeedbackWidget from './FeedbackWidget'; import SelfDeclarationDialog from './SelfDeclarationDialog'; @@ -17,14 +20,103 @@ import { PageContext } from './Page'; import { FETCH_PATH } from './environment'; import { getCookieValue } from './Cookies'; +import { + Accordion, + AccordionSummary, + AccordionDetails +} from "@mui/material"; + +import AddIcon from "@mui/icons-material/Add"; +import RemoveIcon from "@mui/icons-material/Remove"; +import DataObjectOutlinedIcon from "@mui/icons-material/DataObjectOutlined"; +import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; +import CheckOutlinedIcon from "@mui/icons-material/CheckOutlined"; +import StarOutlineOutlinedIcon from "@mui/icons-material/StarOutlineOutlined"; +import OpenInNewIcon from "@mui/icons-material/OpenInNew"; + import './App.css'; +const items = [ + { + icon: DataObjectOutlinedIcon, + title: "STEP Syntax", + desc: "Confirms the uploaded file is a valid STEP Physical File (SPF) in accordance with ISO 10303-21.", + }, + { + icon: DescriptionOutlinedIcon, + title: "IFC Schema", + desc: "Checks against the referenced IFC schema version, including formal propositions and EXPRESS-encoded functions.", + }, + { + icon: CheckOutlinedIcon, + title: "Normative Rules", + desc: "Validates implementer agreements and informal propositions defined in the IFC specification.", + }, + { + icon: StarOutlineOutlinedIcon, + title: "Industry Practices", + desc: "Non-normative checks against common practices and sensible defaults used across the industry.", + }, +]; + +const steps = [ + { n: "01", title: "Upload", desc: "Upload your .ifc file (256mb max)" }, + { n: "02", title: "Validate", desc: "Automated checks run against the IFC standard" }, + { n: "03", title: "Review", desc: "Get a detailed conformity report with errors and warnings" }, +]; + +const faqs = [ + { + q: "Is the Validation Service free?", + a: "Yes. The service is free and provided by buildingSMART international to improve interoperability of IFC.", + }, + { + q: "Do I need an account?", + a: "Yes. An account is required for progress notifications and to gather statistics on authoring tools; developer accounts are excluded from these statistics.", + }, + { + q: "Does it include geometric visualisation?", + a: "The emphasis is on the four validation layers outlined above, while there are rules that relate to geometry there is no geometric visualization of the model or coordination features." + }, + { + q: "What IFC schema versions are supported?", + a: "The supported schemas are IFC2X3, IFC4 and IFC 4.3 (IFC4X3_ADD2)", + }, +]; + +const resources = [ + { + kicker: "buildingSMART", + title: "About buildingSMART", + desc: "In-depth information on everything we do at buildingSMART.org", + href: "https://buildingsmart.org", + }, + { + kicker: "Docs", + title: "User Guide & Documentation", + desc: "Step-by-step guide and technical reference", + href: "https://buildingsmart.github.io/validate/index.html", + }, + { + kicker: "GitHub", + title: "Source Code on GitHub", + desc: "Open-source repository - run it on your own infrastructure", + href: "https://github.com/buildingSMART/validate", + }, + { + kicker: "Forum", + title: "Community Forum", + desc: "Updates, discussions, and feedback", + href: "https://forums.buildingsmart.org/", + }, +]; + function App() { const context = useContext(PageContext); const [isLoggedIn, setLogin] = useState(false); - const [user, setUser] = useState(null) + const [user, setUser] = useState(null); const [prTitle, setPrTitle] = useState("") @@ -41,156 +133,301 @@ function App() { setLogin(true); setUser(data["user_data"]); data["sandbox_info"]["pr_title"] && setPrTitle(data["sandbox_info"]["pr_title"]); - + } }) }, []); document.body.style.overflow = "hidden"; - if (isLoggedIn) { - - return ( -
- + + + - + }} + > + {isLoggedIn && } + - - - -
- + + {context.sandboxId &&

- {context.sandboxId &&

Sandbox for {prTitle}

} + { + false && + } + + {false && + Sandbox for {prTitle}} - - - - - - - + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginLeft: '5px', + gap: '55px' + }}> + + + } + + + +
+ Validate your IFC files against the standard + A free, online platform by buildingSMART for checking IFC file conformity against STEP syntax, IFC schema, and normative specification rules. + Start validating → +
+ + How it checks + Four layers of validation -
- What it is - The bSI Validation Service is a free, online platform for validating IFC files, developed by buildingSMART – with the help of software vendors and bSI projects. - - What it does - - Given an IFC file, the Validation Service provides a judgment of conformity for such file against the IFC standard (schema and specification). - - What is being checked - - The IFC file is valid when it conforms to: - -
    -
  • STEP Syntax The STEP Physical File syntax
  • -
  • IFC Schema An up-to-date (not withdrawn and latest revision) IFC schema referenced in the file, including formal propositions and functions encoded in the EXPRESS schema language
  • -
  • Normative IFC Rules Other normative rules of the IFC specification (e.g. implementer agreements and informal propositions)
  • -
- -
- Additionally, the Validation Service performs non-normative checks including: - -
    -
  • Industry Practices Checking the IFC file against common practice and sensible defaults. None of these checks render the IFC file invalid. Therefore, any issues identified result in warnings rather than errors
  • -
  • bSDD Compliance (disabled) Checking whether references to classifications and properties from bSDD, found in an IFC file, comply with the source definitions in bSDD
  • -
- -
- - What is NOT being checked + + {items.map(({ icon: Icon, title, desc }) => ( + + + {title} + + {desc} + + + ))} + - Outside of the constraints encoded in bSDD, the bSI Validation Service does not check project-specific, national-specific, organization-specific rules or constraints. Case-specific validation is where the mandate of the bSI Validation Service ends. + How it works + Three simple steps + + + {steps.map((s) => ( + + + {s.n} + + + + + {s.title} + + + {s.desc} + + + + ))} + + + FAQ + Common questions + + + + {faqs.map((item, idx) => ( + + + + + + } + > + + {item.q} + + + + + + {item.a} + + + + ))} + - Visualisation + Resources + Go deeper - For multiple reasons, geometric visualisation is not within the scope nor the mandate of the Validation Service. Many errors are invisible in a viewer or unrelated to a geometric representation or prevent visualisation altogether. + + {resources.map((r) => ( + + + + + {r.kicker} + + + {r.title} + + + {r.desc} + + + + ))} + -
-
+
+ + - -
-
+
+
+ - - + {isLoggedIn && } + {isLoggedIn && } - - - - ); - } else { - return ( -
- Thank you! We will review your request to activate your account soon.
-
- Logout -
- ); - } + + + + ); } export default App; \ No newline at end of file diff --git a/frontend/src/Logout.js b/frontend/src/Logout.js index 58c2ccba..4617bd91 100644 --- a/frontend/src/Logout.js +++ b/frontend/src/Logout.js @@ -1,10 +1,11 @@ import './App.css'; import { useState, useEffect } from 'react'; +import { FETCH_PATH } from './environment' function Logout() { const [visible, setVisible] = useState(false); useEffect(() => { - fetch('/api/logout') + fetch(`${FETCH_PATH}/api/logout`) .then(response => response.json()) .then((data) => { window.location.href = data.redirect; diff --git a/frontend/src/ResponsiveAppBar.js b/frontend/src/ResponsiveAppBar.js index 1885daa0..66f51399 100644 --- a/frontend/src/ResponsiveAppBar.js +++ b/frontend/src/ResponsiveAppBar.js @@ -31,40 +31,16 @@ function AppLogo() { ) } -const pages_ = [{ "label": 'Home', "href": "/" }, +const pages = [{ "label": 'Home', "href": "/" }, { "label": "Validation", "href": "/dashboard" -}]; - -const settings_ = [{ "label": 'Home', "href": "/" }, -{ "label": 'Validation', "href": "/dashboard" }, -{ "label": 'Logout', "href": "/logout" }] +},{ "label": 'Logout', "href": "/logout" }] function ResponsiveAppBar({ user }) { const [anchorElNav, setAnchorElNav] = React.useState(null); const [anchorElUser, setAnchorElUser] = React.useState(null); - const context = useContext(PageContext); - - - let pages; - let settings; - - if (context.sandboxId) { - pages = [{ "label": 'Upload', "href": `/sandbox/${context.sandboxId}` }, - { - "label": "Dashboard", - "href": `/sandbox/dashboard/${context.sandboxId}` - }]; - settings = [{ "label": 'Upload new file', "href": `/sandbox/${context.sandboxId}` }, - { "label": 'Dashboard', "href": `/sandbox/dashboard/${context.sandboxId}` }, - { "label": 'Logout', "href": "/logout" }] - } else { - pages = pages_; - settings = settings_; - } - const handleOpenNavMenu = (event) => { setAnchorElNav(event.currentTarget); }; @@ -93,139 +69,61 @@ function ResponsiveAppBar({ user }) { return ( - + - - - BETA - - - - - - - - {pages.map((page) => ( - - - {page["label"]} - - - ))} - - - - - - BETA - - - {pages.map((page) => ( - - ))} - - - - - - + + + {user && + <> + + + + + {user ? (Array.from(user["given_name"])[0] + Array.from(user["family_name"])[0]) : ""} + + + + - {Array.from(user["given_name"])[0] + Array.from(user["family_name"])[0]} - - - - - {settings.map((setting) => ( - - - {setting["label"]} - - - ))} - - + {pages.map((p) => ( + + + {p.label} + + + ))} + + + + } + + {!user && + + Sign In + + }