more database work, added search route, starting frontend new location form

This commit is contained in:
2022-04-02 23:15:23 -04:00
parent cc60aa59d5
commit 03dd723c57
14 changed files with 431 additions and 1110 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -6,71 +6,6 @@ import (
"github.com/asdine/storm/v3" "github.com/asdine/storm/v3"
) )
// Location is a top level component that starts the containerization process
type Location struct {
ID int `storm:"id,increment,index"`
Name string `storm:"unique"`
Description string
CoverPhoto string // A "cover photo" for the location
Photos []string // A list of additional photos for the location
Rooms []Room
Notes string
Address string
SquareFeet int
Latitude string
Longitude string
DatePurchased string
PurchasePrice string
CurrentValue string
}
// Room is a containerized area at a location
type Room struct {
ID int `storm:"id,increment,index"`
Name string
Description string
CoverPhoto string // A "cover photo" for the room
Photos []string // A list of additional photos for the room
Paint string // Details about the paint
Notes string
Cabinets []Cabinet
Items []Item
SquareFeet int
LocationID int //Which location room is assigned to
LocationName string // Location name room belongs to
}
// Cabinet is a containerized area in a room
type Cabinet struct {
ID int `storm:"id, increment"`
RoomID int // Room ID that the cabinet is assigned to
RoomName string // Room name cabinet belongs to
CoverPhoto string // A "Cover photo" for this item
Items []Item // List of items in the cabinet
Name string
Notes string
}
// Item is contained inside a room or cabinet
type Item struct {
ID int `storm:"id, increment"`
LocType string // Can be Room or Cabinet to show where it is stored
RoomID int // Room ID that item is assigned to (can also be in a cabinet)
RoomName string // Room name that item is assigned to
CabinetID int //The cabinet id that an item is assigned to
CabinetName string // The name of the cabinet it belongs to
CoverPhoto string // A "cover photo" for the item
Photos []string // A list of additional photos for the item
Count int // If item has duplicates
Name string
Product string
Serial string
Warranty string
Notes string
Files []string //filepath to any files relevant to this item
}
// Location Routes // Location Routes
//SetupDatabase initializes the storm/bbolt database //SetupDatabase initializes the storm/bbolt database
@@ -301,3 +236,51 @@ func (s *Server) DeleteItem(item Item) error {
} }
return nil return nil
} }
// Misc calls
type SearchResults struct {
Locations []Location `json:"locations"`
Rooms []Room `json:"rooms"`
Cabinets []Cabinet `json:"cabinets"`
Items []Item `json:"items"`
}
// SearchAllByField searches the entire database (locs, rooms, cabinets, items) by the field and search term passed in
func (s *Server) SearchAllByField(fieldFilter string, searchTerm string) (results SearchResults, err error) {
s.Log.Info().Msgf("Searching all items for term: %s", searchTerm)
var locs []Location
var rooms []Room
var cabinets []Cabinet
var items []Item
results = SearchResults{}
err = s.Database.Find(fieldFilter, searchTerm, &locs)
if err != nil && err != storm.ErrNotFound {
s.Log.Error().Msgf("Unable to search locations in database with term: %s :error: %s ", searchTerm, err)
return results, err
}
err = s.Database.Find(fieldFilter, searchTerm, &rooms)
if err != nil && err != storm.ErrNotFound {
s.Log.Error().Msgf("Unable to search rooms in database with term: %s error: %s ", searchTerm, err)
return results, err
}
err = s.Database.Find(fieldFilter, searchTerm, &cabinets)
if err != nil && err != storm.ErrNotFound {
s.Log.Error().Msgf("Unable to search cabinets in database with term: %s error: %s ", searchTerm, err)
return results, err
}
err = s.Database.Find(fieldFilter, searchTerm, &items)
if err != nil && err != storm.ErrNotFound {
s.Log.Error().Msgf("Unable to search items in database with term: %s error: %s ", searchTerm, err)
return results, err
}
results.Locations = locs
results.Rooms = rooms
results.Cabinets = cabinets
results.Items = items
return results, nil
}

67
database_structs.go Normal file
View File

@@ -0,0 +1,67 @@
package main
// Location is a top level component that starts the containerization process
type Location struct {
ID int `storm:"id,increment,index"`
Name string `storm:"unique"`
Description string
CoverPhoto string // A "cover photo" for the location
Photos []string // A list of additional photos for the location
Rooms []Room
Notes string
Address string
SquareFeet int
Latitude string
Longitude string
DatePurchased string
PurchasePrice string
CurrentValue string
}
// Room is a containerized area at a location
type Room struct {
ID int `storm:"id,increment,index"`
Name string
Description string
CoverPhoto string // A "cover photo" for the room
Photos []string // A list of additional photos for the room
Paint string // Details about the paint
Notes string
Cabinets []Cabinet
Items []Item
SquareFeet int
LocationID int //Which location room is assigned to
LocationName string // Location name room belongs to
}
// Cabinet is a containerized area in a room
type Cabinet struct {
ID int `storm:"id, increment"`
RoomID int // Room ID that the cabinet is assigned to
RoomName string // Room name cabinet belongs to
CoverPhoto string // A "Cover photo" for this item
Items []Item // List of items in the cabinet
Name string
Notes string
}
// Item is contained inside a room or cabinet
type Item struct {
ID int `storm:"id, increment"`
LocType string // Can be Room or Cabinet to show where it is stored
RoomID int // Room ID that item is assigned to (can also be in a cabinet)
RoomName string // Room name that item is assigned to
CabinetID int //The cabinet id that an item is assigned to
CabinetName string // The name of the cabinet it belongs to
CoverPhoto string // A "cover photo" for the item
Photos []string // A list of additional photos for the item
Count int // If item has duplicates
Name string
Product string
Serial string
Warranty string
Notes string
DatePurchased string
Files []string //filepath to any files relevant to this item
}

View File

@@ -2030,11 +2030,11 @@
} }
}, },
"@mantine/core": { "@mantine/core": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-4.1.0.tgz", "resolved": "https://registry.npmjs.org/@mantine/core/-/core-4.1.1.tgz",
"integrity": "sha512-uEHGssKveDgGHhbBrgVqp8o12m0oQGLBKH3D8bkrca1GB905ZHuj8CG+i/ojBhqdalfUwqcYGRpwwALtD+XfJg==", "integrity": "sha512-7eTv/vXKX863ri3c6zVbxozsAeA8B0iN31j3/dKs0K3y5Vd9+cgAy59WQk2RBGRlWdln7gtLnELePyQz+WlXLQ==",
"requires": { "requires": {
"@mantine/styles": "4.1.0", "@mantine/styles": "4.1.1",
"@popperjs/core": "^2.9.3", "@popperjs/core": "^2.9.3",
"@radix-ui/react-scroll-area": "^0.1.1", "@radix-ui/react-scroll-area": "^0.1.1",
"clsx": "^1.1.1", "clsx": "^1.1.1",
@@ -2043,9 +2043,9 @@
} }
}, },
"@mantine/dates": { "@mantine/dates": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-4.1.0.tgz", "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-4.1.1.tgz",
"integrity": "sha512-kdKQ9PRGbYe1YhRlqWVUVGG7IKHjdIWMX3XhSFbWWLkfUxqSG4dhwNeAZIcbHXDZhFT9xIifFlBlDiN7JIOmtA==", "integrity": "sha512-IUATTmne8sE4CwUngDS11zXk9xrpDuyBZSJ2LmHa0aiIm2GUTloPutLyK7zY2umaJVoRok6ji9Nlud7eEEAyYg==",
"requires": { "requires": {
"@popperjs/core": "^2.9.3", "@popperjs/core": "^2.9.3",
"clsx": "^1.1.1", "clsx": "^1.1.1",
@@ -2060,10 +2060,15 @@
"react-dropzone": "^11.4.2" "react-dropzone": "^11.4.2"
} }
}, },
"@mantine/form": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@mantine/form/-/form-4.1.1.tgz",
"integrity": "sha512-Kh7lJ+JcLynCxpqUDmc5zpj/Jd/ZLpHCKnGM4TnfhV45lRlGhDQQtteKJ99XneYu2s23EhsLXfBIhD4RadHZ8g=="
},
"@mantine/hooks": { "@mantine/hooks": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-4.1.0.tgz", "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-4.1.1.tgz",
"integrity": "sha512-bvVvHDDfYqdIxl7n+lBBwSIkcqInv6kK+fxvEfFBOUEzN6KbpJaPdaYXP788x64uFbA7AODQjdtOhk3tMyQA8Q==" "integrity": "sha512-uVLVT1Qc7rt3kXy25efUVc509Uv3HPNPMyJaPEGM+o9RWy0k3Mo5Zp3meVfUL7PmjY179RlHmrGtxprdpiDZaA=="
}, },
"@mantine/notifications": { "@mantine/notifications": {
"version": "4.1.0", "version": "4.1.0",
@@ -2075,9 +2080,9 @@
} }
}, },
"@mantine/styles": { "@mantine/styles": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-4.1.0.tgz", "resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-4.1.1.tgz",
"integrity": "sha512-mWFNSE5DqE/5C9TDYIkQVbTef8QyWnW8a8MADHl6S52K0iGU8nqw4jnyozB+6y9JEIxdl+sp0o16L2JnAsq7bA==", "integrity": "sha512-ZTfjqugTrqAQatgmdA0R+smUCIwPZCHykxKA5HwQzuJZh6/9TwaPozdTP7yOKAVyjBDnnAQda2PPZ1Gz1PrXqg==",
"requires": { "requires": {
"@emotion/cache": "^11.7.1", "@emotion/cache": "^11.7.1",
"@emotion/react": "^11.7.1", "@emotion/react": "^11.7.1",
@@ -13172,9 +13177,9 @@
"integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==" "integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw=="
}, },
"use-isomorphic-layout-effect": { "use-isomorphic-layout-effect": {
"version": "1.1.1", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
"integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==" "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
}, },
"use-latest": { "use-latest": {
"version": "1.2.0", "version": "1.2.0",

View File

@@ -3,10 +3,11 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@mantine/core": "^4.1.0", "@mantine/core": "^4.1.1",
"@mantine/dates": "^4.1.0", "@mantine/dates": "^4.1.1",
"@mantine/dropzone": "^4.1.0", "@mantine/dropzone": "^4.1.0",
"@mantine/hooks": "^4.1.0", "@mantine/form": "^4.1.1",
"@mantine/hooks": "^4.1.1",
"@mantine/notifications": "^4.1.0", "@mantine/notifications": "^4.1.0",
"@testing-library/jest-dom": "^5.16.3", "@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4", "@testing-library/react": "^12.1.4",

View File

@@ -0,0 +1,61 @@
import React from 'react';
import { Text, Button, Card, Group, Menu, Image, Badge } from '@mantine/core'
import { useAtom } from 'jotai';
import { useNavigate } from "react-router-dom";
import { activePageAtom, roomFilterAtom, serverConfigAtom } from '../../state/main';
function LocationCard(props) {
const {location, idx} = props
const [serverConfig] = useAtom(serverConfigAtom)
const [, setRoomsFilter] = useAtom(roomFilterAtom)
const [, setActivePage] = useAtom(activePageAtom)
const navigate = useNavigate();
const setRoomNumber = (rooms) => {
if (rooms === null) {
return <Text>0 Rooms</Text>
} else if (rooms.length > 1) {
return <Text>{rooms.length} Rooms</Text>
} else {
return <Text>1 Room</Text>
}
}
const navigateToRooms = (locationID, locationName) => {
setActivePage("rooms")
setRoomsFilter({"filterType": "location", "locationID": locationID, "commonName": "location", "metadata": locationName})
navigate("/rooms")
}
return (
<Card key={`${idx} - ${location.ID}`} shadow="md" padding="md">
<Card.Section>
{location.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${location.Name}/${location.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
<Group position='right' style={{position: 'absolute', top: '5px', right: '5px', backgroundColor: 'grey', borderRadius: '25%'}}>
<Menu>
<Menu.Label>Edit</Menu.Label>
<Menu.Label>Delete</Menu.Label>
</Menu>
</Group>
</Card.Section>
<Group position="apart">
<Text weight={500}>{location.Name}</Text>
<Badge variant="light">
{ setRoomNumber(location.Rooms) }
</Badge>
</Group>
<Text size="sm">{location.Description}</Text>
<Group>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Details</Button>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Rooms</Button>
</Group>
</Card>
);
}
export default LocationCard;

View File

@@ -0,0 +1,63 @@
import React from 'react';
import { Text, Button, Card, Group, Menu, Image, Badge } from '@mantine/core'
import { useAtom } from 'jotai';
import { useNavigate } from "react-router-dom";
import { activePageAtom, roomFilterAtom, serverConfigAtom } from '../../state/main';
function RoomCard(props) {
const {room, idx} = props
const [serverConfig] = useAtom(serverConfigAtom)
const [, setRoomsFilter] = useAtom(roomFilterAtom)
const [, setActivePage] = useAtom(activePageAtom)
const navigate = useNavigate();
const setItemAndCabinetNumber = (category, name) => {
if (category === null) {
return <Text>0 {name}s</Text>
} else if (category.length > 1) {
return <Text>{category.length} {name}s</Text>
} else {
return <Text>1 {name}</Text>
}
}
const navigateToCabinets = (roomID, roomName) => {
setActivePage("cabinets")
setRoomsFilter({"filterType": "room", "roomID": roomID, "commonName": "room", "metadata": roomName})
navigate("/cabinets")
}
return (
<Card key={`${idx} - ${room.ID}`} component="a" onClick={(e) => {}} shadow="sm" padding="md">
<Card.Section>
{room.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${room.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{room.Name}</Text>
<Group>
<Badge color="pink" variant="light">
{room.LocationName}
</Badge>
<Badge variant='light'>
{setItemAndCabinetNumber(room.Cabinets, "Cabinet")}
</Badge>
<Badge color='teal' variant='light'>
{setItemAndCabinetNumber(room.Items, "Item")}
</Badge>
</Group>
</Group>
<Text size="sm">{room.Description}</Text>
<Group>
<Button onClick={() => console.log("test")}>View Details</Button>
<Button onClick={() => navigateToCabinets(room.id, room.Name)}>View Cabinets</Button>
<Button onClick={() => console.log("test")}>View Items</Button>
</Group>
</Card>
);
}
export default RoomCard;

View File

@@ -0,0 +1,26 @@
import React, {useState, useEffect} from 'react';
import { Text, Title, TextInput, Button, NumberInput, } from '@mantine/core'
import { DatePicker } from '@mantine/dates';
import { useForm } from '@mantine/form';
import { useAtom } from 'jotai';
import { serverConfigAtom } from '../../state/main'
function LocationForm(props) {
const {location, modify: bool} = props
const [opened, setOpened] = useState(false);
const [serverConfig] = useAtom(serverConfigAtom)
return (
<>
<Title>Location Form</Title>
<Text>This is the homepage!</Text>
</>
);
}
export default LocationForm;

View File

@@ -1,5 +1,4 @@
import React, {useState, useEffect, useContext, createContext} from 'react'; import React, {useState, useEffect, useContext, createContext} from 'react';
import APIContext from '../../App';
import { Text } from '@mantine/core' import { Text } from '@mantine/core'
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { serverConfigAtom } from '../../state/main' import { serverConfigAtom } from '../../state/main'

View File

@@ -1,25 +1,26 @@
import React, {useState, useEffect, useContext, createContext} from 'react'; import React, {useState, useEffect } from 'react';
import { useAtom } from 'jotai' import { useAtom } from 'jotai'
import { activePageAtom, roomFilterAtom, serverConfigAtom } from '../../state/main'; import { serverConfigAtom } from '../../state/main';
import { Text, Loader, Center, Card, Image, Badge, Button, SimpleGrid, Group, Title } from '@mantine/core' import { HiPlus } from 'react-icons/hi'
import { useNavigate } from "react-router-dom"; import { Loader, Center, SimpleGrid, Title, Group, Button, Divider } from '@mantine/core'
import { useNotifications } from '@mantine/notifications'; import { useNotifications } from '@mantine/notifications';
import { backendAPI } from '../../services/backend-api'; import { backendAPI } from '../../services/backend-api';
import LocationCard from '../cards/LocationCard';
function LocationsPage(props) { function LocationsPage() {
// const [opened, setOpened] = useState(false); // const [opened, setOpened] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [locations, setLocations] = useState([]) const [locations, setLocations] = useState([])
const [serverConfig] = useAtom(serverConfigAtom) const [serverConfig] = useAtom(serverConfigAtom)
const [, setRoomsFilter] = useAtom(roomFilterAtom)
const [, setActivePage] = useAtom(activePageAtom)
const notifications = useNotifications(); const notifications = useNotifications();
const navigate = useNavigate();
useEffect(() => { useEffect(() => {
console.log("LOADING LOCATIONS PAGE!") console.log("LOADING LOCATIONS PAGE!")
@@ -46,27 +47,12 @@ function LocationsPage(props) {
}, []) }, [])
const navigateToRooms = (locationID, locationName) => {
setActivePage("rooms")
setRoomsFilter({"filterType": "location", "locationID": locationID, "commonName": "location", "metadata": locationName})
navigate("/rooms")
}
const setRoomNumber = (location) => {
if (location.Rooms === null) {
return <Text>0 Rooms</Text>
} else if (location.Rooms.length > 1) {
return <Text>{location.Rooms.length} Rooms</Text>
} else {
return <Text>1 Room</Text>
}
}
return ( return (
<> <>
<Center>{ isLoading && <Loader size="xl" variant="bars" />}</Center> <Center>{ isLoading && <Loader size="xl" variant="bars" />}</Center>
<Center><Title order={1}>Locations</Title></Center> <Center><Title order={1}>Locations</Title></Center>
<Button leftIcon={<HiPlus />}>Add New Location</Button>
<Divider />
<SimpleGrid <SimpleGrid
spacing="md" spacing="md"
cols={4} cols={4}
@@ -78,23 +64,7 @@ function LocationsPage(props) {
> >
{ locations.map((location, idx) => { locations.map((location, idx) =>
<Card key={`${idx} - ${location.ID}`} shadow="md" padding="md"> <LocationCard location={location} idx={idx}></LocationCard>
<Card.Section>
{location.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${location.Name}/${location.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{location.Name}</Text>
<Badge variant="light">
{ setRoomNumber(location) }
</Badge>
</Group>
<Text size="sm">{location.Description}</Text>
<Group>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Details</Button>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Rooms</Button>
</Group>
</Card>
)} )}
</SimpleGrid> </SimpleGrid>
</> </>

View File

@@ -6,6 +6,7 @@ import { useLocation } from "react-router-dom";
import { useNotifications } from '@mantine/notifications'; import { useNotifications } from '@mantine/notifications';
import { backendAPI } from '../../services/backend-api'; import { backendAPI } from '../../services/backend-api';
import RoomCard from '../cards/RoomCard';
function RoomsPage(props) { function RoomsPage(props) {
@@ -27,7 +28,7 @@ function RoomsPage(props) {
console.log("CURRENT STATE: ", state) console.log("CURRENT STATE: ", state)
// if we are filtering by location // if we are filtering by location
if (roomFilter.locationID) { if (roomFilter.locationID) {
url = `rooms/${roomFilter.locationID}` url = `locations/${roomFilter.locationID}/rooms`
} }
backendAPI.get(url).then(results => { backendAPI.get(url).then(results => {
console.log("ROOMS: ", results) console.log("ROOMS: ", results)
@@ -50,10 +51,10 @@ function RoomsPage(props) {
}, [roomFilter]) }, [roomFilter])
// Check if filter changes for this page and refresh results // Check if filter changes for this page and refresh results
useEffect(() => { // useEffect(() => {
console.log("CURRENT ROOM FILTER: ", roomFilter) // console.log("CURRENT ROOM FILTER: ", roomFilter)
}, [roomFilter, setRoomFilter]) // }, [roomFilter, setRoomFilter])
const removeFilterButton = ( const removeFilterButton = (
<ActionIcon size="xs" color="blue" radius="xl" variant="transparent"> <ActionIcon size="xs" color="blue" radius="xl" variant="transparent">
@@ -83,30 +84,7 @@ function RoomsPage(props) {
]} ]}
> >
{ rooms.map((room, idx) => { rooms.map((room, idx) =>
<Card key={`${room.ID}`} component="a" onClick={(e) => {}} shadow="sm" padding="md"> <RoomCard room={room} idx={idx}></RoomCard>
<Card.Section>
{room.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${room.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{room.Name}</Text>
<Group>
<Badge color="pink" variant="light">
{room.LocationName}
</Badge>
<Badge variant='light'>
{room.Cabinets === null ? 0 : room.Cabinets.length} Cabinets
</Badge>
<Badge color='teal' variant='light'>
{room.Cabinets === null ? 0 : room.Cabinets.length} Items
</Badge>
</Group>
</Group>
<Text size="sm">{room.Description}</Text>
<Group>
<Button onClick={() => console.log("test")}>View Details</Button>
<Button onClick={() => console.log("test")}>View Rooms</Button>
</Group>
</Card>
)} )}
</SimpleGrid> </SimpleGrid>
</> </>

View File

@@ -19,6 +19,20 @@ func (s *Server) GetAllItemsHandler(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(items) return c.Status(fiber.StatusOK).JSON(items)
} }
// GetItemHandler returns a single item from an ID
func (s *Server) GetItemHandler(c *fiber.Ctx) error {
itemID, err := c.ParamsInt("itemID")
if err != nil {
return err
}
room, err := s.GetItem(itemID)
if err != nil {
s.Log.Err(err).Msgf("Unable to fetch item with id: %d", itemID)
return err
}
return c.Status(fiber.StatusOK).JSON(room)
}
// GetAllItemsAtRoomHandler gets all items in a room // GetAllItemsAtRoomHandler gets all items in a room
func (s *Server) GetAllItemsAtRoomHandler(c *fiber.Ctx) error { func (s *Server) GetAllItemsAtRoomHandler(c *fiber.Ctx) error {
roomID, err := c.ParamsInt("roomID") roomID, err := c.ParamsInt("roomID")

22
handlers_other.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
// SearchAllByField searches all of the DB by specified field
func (s *Server) SearchAllHandler(c *fiber.Ctx) error {
searchField := c.Query("field", "Name")
searchTerm := c.Query("term")
s.Log.Debug().Msgf("Search by term: %s in all items at field: %s", searchTerm, searchField)
results, err := s.SearchAllByField(searchField, searchTerm)
if err != nil {
s.Log.Error().Msgf("SearchAllByField failed to return results: %s ", err)
return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Database failure! error: %s", err))
}
return c.Status(fiber.StatusOK).JSON(results)
}

View File

@@ -110,17 +110,19 @@ func main() {
// Cabinet Routes // Cabinet Routes
server.WebServer.Get("/api/cabinets", server.GetAllCabinetsHandler) server.WebServer.Get("/api/cabinets", server.GetAllCabinetsHandler)
server.WebServer.Get("/api/cabinets/:cabinetID", server.GetCabinetHandler) server.WebServer.Get("/api/cabinets/:cabinetID", server.GetCabinetHandler)
server.WebServer.Post("/api/cabinets/:roomID/new", server.AddNewCabinetHandler)
server.WebServer.Get("/api/cabinets/:cabinetID/items", server.GetAllItemsAtCabinetHandler) server.WebServer.Get("/api/cabinets/:cabinetID/items", server.GetAllItemsAtCabinetHandler)
server.WebServer.Delete("/api/cabinets/:cabinetID", server.DeleteCabinetHandler) server.WebServer.Delete("/api/cabinets/:cabinetID", server.DeleteCabinetHandler)
// Item Routes // Item Routes
server.WebServer.Get("/api/items", server.GetAllItemsHandler) server.WebServer.Get("/api/items", server.GetAllItemsHandler)
server.WebServer.Get("/api/items/room/:roomID", server.GetAllItemsAtRoomHandler) server.WebServer.Get("/api/items/:itemID", server.GetItemHandler)
server.WebServer.Get("/api/items/cabinet/:cabinetID", server.GetAllItemsAtCabinetHandler)
server.WebServer.Post("/api/items/cabinet/:cabinetID/new", server.AddNewItemHandler) server.WebServer.Post("/api/items/cabinet/:cabinetID/new", server.AddNewItemHandler)
server.WebServer.Post("/api/items/room/:roomID/new", server.AddNewItemHandler) server.WebServer.Post("/api/items/room/:roomID/new", server.AddNewItemHandler)
server.WebServer.Delete("/api/items/:itemID", server.DeleteItemHandler) server.WebServer.Delete("/api/items/:itemID", server.DeleteItemHandler)
// Misc Routes
server.WebServer.Get("/api/search/all", server.SearchAllHandler)
// Start Server
fmt.Println("Everything ready, starting server! ", fmt.Sprintf(":%s", server.Config.Server.Port)) fmt.Println("Everything ready, starting server! ", fmt.Sprintf(":%s", server.Config.Server.Port))
server.WebServer.Listen(fmt.Sprintf(":%s", server.Config.Server.Port)) server.WebServer.Listen(fmt.Sprintf(":%s", server.Config.Server.Port))
} }