@@ -36,14 +36,8 @@ internal struct PlacemarkControllerV1: RouteCollection {
3636try placemark. register ( collection: PlacemarkSubmissionControllerV1 ( ) )
3737}
3838
39- // GET /placemarks/v1/features
40- routes. get ( " features " , use: listPlacemarkFeatures)
41- // GET /placemarks/v1/techniques
42- routes. get ( " techniques " , use: listPlacemarkTechniques)
43- // GET /placemarks/v1/benefits
44- routes. get ( " benefits " , use: listPlacemarkBenefits)
45- // GET /placemarks/v1/hazards
46- routes. get ( " hazards " , use: listPlacemarkHazards)
39+ // GET /placemarks/v1/properties
40+ routes. get ( " properties " , use: listPlacemarkProperties)
4741}
4842
4943func listPlacemarks( req: Request ) throws -> EventLoopFuture < Page < GEOSwift . Feature > > {
@@ -53,178 +47,23 @@ internal struct PlacemarkControllerV1: RouteCollection {
5347}
5448}
5549
56- func createPlacemarkRaw( req: Request ) throws -> EventLoopFuture < Placemark . Public > {
57- let user = try req. auth. require ( UserModel . self, with: . bearer, in: req)
58- // Validate and decode data
59- try Placemark . Create. validate ( content: req)
60- let create = try req. content. decode ( Placemark . Create. self)
61-
62- // Do additional validations
63- // TODO: Check for near spots (e.g. < 20m)
64-
65- let placemarkKindFuture = PlacemarkModel . Kind. query ( on: req. db)
66- . filter ( \. $humanId== create. kind. rawValue)
67- . first ( )
68- . unwrap ( or: Abort ( . notFound, reason: " Placemark type not found " ) )
69-
70- // Create Placemark object
71- let placemarkFuture = placemarkKindFuture. flatMapThrowing { kindin
72- try PlacemarkModel (
73- name: create. name,
74- latitude: create. latitude,
75- longitude: create. longitude,
76- kindId: kind. requireID ( ) ,
77- state: . private,
78- creatorId: user. requireID ( )
79- )
80- }
81-
82- // Save Placemark in database
83- let createPlacemarkFuture = placemarkFuture. passthroughAfter { $0. create ( on: req. db) }
84-
85- // Add properties
86- let addPropertiesFuture = { ( details: PlacemarkModel . Details ) -> EventLoopFuture < Void > in
87- req. eventLoop. makeSucceededFuture ( create. properties)
88- . sequencedFlatMapEach { kind, propertyIdsin
89- req. eventLoop. makeSucceededFuture ( propertyIds)
90- . sequencedFlatMapEach { propertyIdin
91- PlacemarkModel . Details. Property. query ( on: req. db)
92- . filter ( \. $kind== kind)
93- . filter ( \. $humanId== propertyId)
94- . first ( )
95- . unwrap ( or: Abort (
96- . badRequest,
97- reason: " Invalid property: { \" kind \" : \" \( kind) \" , \" id \" : \" \( propertyId) \" } "
98- ) )
99- . flatMap { propertyin
100- details. $properties. attach ( property, method: . ifNotExists, on: req. db)
101- }
102- }
103- }
104- }
105-
106- // Create placemark details
107- let createDetailsFuture = createPlacemarkFuture
108- . passthroughAfter { placemark-> EventLoopFuture < Void > in
109- let details = try PlacemarkModel . Details (
110- placemarkId: placemark. requireID ( ) ,
111- caption: create. caption,
112- images: ( create. images?? [ ] ) . map { $0. absoluteString}
113- )
114-
115- return details. create ( on: req. db)
116- . transform ( to: details)
117- . flatMap ( addPropertiesFuture)
118- }
119-
120- // Trigger satellite view loading
121- let loadSatelliteViewFuture = createDetailsFuture
122- . passthroughAfter { placemark-> EventLoopFuture < Void > in
123- if req. application. environment== . testing{
124- return req. eventLoop. makeSucceededFuture ( ( ) )
125- } else {
126- return req. queues ( . placemarks)
127- . dispatch (
128- PlacemarkSatelliteViewJob . self,
129- . init(
130- placemarkId: try placemark. requireID ( ) ,
131- latitude: placemark. latitude,
132- longitude: placemark. longitude
133- )
134- )
135- }
136- }
137-
138- // Trigger location reverse geocoding
139- let reverseGeocodeLocationFuture = loadSatelliteViewFuture
140- . passthroughAfter { placemark-> EventLoopFuture < Void > in
141- if req. application. environment== . testing{
142- return req. eventLoop. makeSucceededFuture ( ( ) )
143- } else {
144- return req. queues ( . placemarks)
145- . dispatch (
146- PlacemarkLocationJob . self,
147- . init(
148- placemarkId: try placemark. requireID ( ) ,
149- latitude: placemark. latitude,
150- longitude: placemark. longitude
151- )
152- )
153- }
154- }
155-
156- return reverseGeocodeLocationFuture
157- . flatMap { $0. asPublic ( on: req. db) }
158- //.flatMap { $0.encodeResponse(status: .created, for: req) }
159- }
160-
16150func createPlacemark( req: Request ) throws -> EventLoopFuture < Response > {
162- try self . createPlacemarkRaw ( req: req)
51+ try PlacemarkService ( req: req) . createPlacemark ( )
16352. flatMapThrowing { try $0. asGeoJSON ( ) }
16453. flatMap { $0. encodeResponse ( status: . created, for: req) }
16554}
16655
167- func getPlacemarkRaw( req: Request ) throws -> EventLoopFuture < Placemark . Public > {
168- let placemarkId = try req. parameters. require ( " placemarkId " , as: UUID . self)
169- return PlacemarkModel . find ( placemarkId, on: req. db)
170- . unwrap ( or: Abort ( . notFound, reason: " Placemark not found " ) )
171- . flatMap { $0. asPublic ( on: req. db) }
172- }
173-
17456func getPlacemark( req: Request ) throws -> EventLoopFuture < GEOSwift . Feature > {
175- try getPlacemarkRaw ( req: req) . flatMapThrowing { try $0. asGeoJSON ( ) }
57+ try PlacemarkService ( req: req) . getPlacemark ( )
58+ . flatMapThrowing { try $0. asGeoJSON ( ) }
17659}
17760
17861func deletePlacemark( req: Request ) throws -> EventLoopFuture < HTTPStatus > {
179- let user = try req. auth. require ( UserModel . self, with: . bearer, in: req)
180- let placemarkId = try req. parameters. require ( " placemarkId " , as: UUID . self)
181-
182- let placemarkFuture = PlacemarkModel . find ( placemarkId, on: req. db)
183- . unwrap ( or: Abort ( . notFound, reason: " Placemark not found " ) )
184-
185- // Do additional validations
186- let guardAuthorizedFuture = placemarkFuture. guard ( { placemarkin
187- placemark. $creator. id== user. id
188- } , else: Abort ( . forbidden, reason: " You cannot delete someone else's placemark! " ) )
189-
190- let deleteDetailsFuture = guardAuthorizedFuture
191- . passthroughAfter { _in
192- PlacemarkModel . Details. query ( on: req. db)
193- . with ( \. $placemark)
194- . filter ( \. $placemark. $id== placemarkId)
195- . all ( )
196- . flatMap { $0. delete ( on: req. db) }
197- }
198-
199- return deleteDetailsFuture
200- . flatMap { $0. delete ( on: req. db) }
201- . transform ( to: . noContent)
202- }
203-
204- func listPlacemarkFeatures( req: Request ) -> EventLoopFuture < [ Placemark . Property . Localized ] > {
205- listProperties ( ofKind: . feature, in: req. db)
206- }
207-
208- func listPlacemarkTechniques( req: Request ) -> EventLoopFuture < [ Placemark . Property . Localized ] > {
209- listProperties ( ofKind: . technique, in: req. db)
210- }
211-
212- func listPlacemarkBenefits( req: Request ) -> EventLoopFuture < [ Placemark . Property . Localized ] > {
213- listProperties ( ofKind: . benefit, in: req. db)
214- }
215-
216- func listPlacemarkHazards( req: Request ) -> EventLoopFuture < [ Placemark . Property . Localized ] > {
217- listProperties ( ofKind: . hazard, in: req. db)
62+ try PlacemarkService ( req: req) . deletePlacemark ( )
21863}
21964
220- private func listProperties(
221- ofKind kind: Placemark . Property . Kind ,
222- in database: Database
223- ) -> EventLoopFuture < [ Placemark . Property . Localized ] > {
224- PlacemarkModel . Property. query ( on: database)
225- . filter ( \. $kind== kind)
226- . all ( )
227- . flatMapEachThrowing { try $0. localized ( in: . en) }
65+ func listPlacemarkProperties( req: Request ) throws -> EventLoopFuture < [ Placemark . Property . Localized ] > {
66+ try PlacemarkService ( req: req) . listProperties ( )
22867}
22968
23069}