33package androidmakers.service.graphql
44
55import androidmakers.service.Sessionize
6- import androidmakers.service.context.AuthenticationContext
7- import androidmakers.service.context.bookmarksKeyFactory
8- import androidmakers.service.context.datastore
9- import androidmakers.service.context.uid
10- import androidmakers.service.context.updateMaxAge
11- import com.apollographql.apollo.annotations.*
6+ import androidmakers.service.context.*
7+ import com.apollographql.apollo.annotations.ApolloExperimental
128import com.apollographql.apollo.api.ExecutionContext
9+ import com.apollographql.apollo.api.Optional
1310import com.apollographql.apollo.execution.StringCoercing
1411import com.apollographql.execution.annotation.GraphQLDefault
1512import com.apollographql.execution.annotation.GraphQLMutation
@@ -19,8 +16,11 @@ import com.google.cloud.datastore.BooleanValue
1916import com.google.cloud.datastore.Cursor
2017import com.google.cloud.datastore.Entity
2118import com.google.cloud.datastore.Query
22- import com.google.rpc.context.AttributeContext
19+ import com.google.cloud.datastore.StructuredQuery
20+ import kotlinx.datetime.Instant
2321import kotlinx.datetime.LocalDateTime
22+ import kotlinx.datetime.toInstant
23+ import kotlin.time.Clock
2424
2525const val KIND_BOOKMARKS = " Bookmarks"
2626const val KIND_FEED_ITEMS = " FeedItems"
@@ -35,11 +35,11 @@ typealias Markdown = String
3535typealias ID = String
3636
3737class FeedItemInput (
38- val title : String ,
39- val markdown : Markdown
38+ val title : Optional < String ?> ,
39+ val markdown : Optional < Markdown ?>,
4040)
4141
42- internal val adminEmails = setOf (" martinbonninandroid@gmail.com " , " reno.mathieu@gmail.com " )
42+ internal val adminUids = setOf (" AY7jNYS4EpNhRHBxW89LjomGCtl1 " )
4343
4444sealed interface FeedItemResult
4545
@@ -50,32 +50,69 @@ data class FeedItemSuccess(
5050
5151class FeedItem (
5252 val id : ID ,
53+ val createdAt : GraphQLInstant ,
5354 val title : String ,
5455 val markdown : Markdown
5556)
5657
5758@GraphQLMutation
5859class RootMutation {
5960 fun updateFeedItem (executionContext : ExecutionContext , id : ID , feedItem : FeedItemInput ): FeedItemResult {
60- TODO ()
61- }
62- fun addFeedItem (executionContext : ExecutionContext , feedItem : FeedItemInput ): FeedItemResult {
6361 val authenticationContext = executionContext.get(AuthenticationContext )!!
64- val email = authenticationContext.email
65- check(email != null ) {
66- " Adding to the feed requires authentication"
62+ if (authenticationContext.uid !in adminUids) {
63+ throw Error (" Only admins can add feed items" )
6764 }
6865
69- if (email !in adminEmails) {
66+ val datastore = executionContext.datastore()
67+ val key = datastore.newKeyFactory().setKind(KIND_FEED_ITEMS ).newKey(id.toLong())
68+ val entity = datastore.get(key)
69+ if (entity == null ) {
70+ return FeedItemFailure (" No item found for id $id " )
71+ }
72+ val updatedEntity = Entity .newBuilder(entity)
73+ .apply {
74+ if (feedItem.title.getOrNull() != null ) {
75+ set(" title" , feedItem.title.getOrThrow())
76+ }
77+ if (feedItem.markdown.getOrNull() != null ) {
78+ set(" markdown" , feedItem.markdown.getOrThrow())
79+ }
80+ }
81+ .build()
82+
83+ val newEntity = datastore.put(updatedEntity)
84+
85+ return FeedItemSuccess (
86+ FeedItem (
87+ id = id,
88+ title = newEntity.getString(" title" ),
89+ markdown = newEntity.getString(" markdown" ),
90+ createdAt = Instant .parse(newEntity.getString(" createdAt" ))
91+ )
92+ )
93+ }
94+
95+ fun addFeedItem (executionContext : ExecutionContext , feedItem : FeedItemInput ): FeedItemResult {
96+ val authenticationContext = executionContext.get(AuthenticationContext )!!
97+ if (authenticationContext.uid !in adminUids) {
7098 throw Error (" Only admins can add feed items" )
7199 }
72100
73101 val datastore = executionContext.datastore()
74102
103+ check(feedItem.title.getOrNull() != null ) {
104+ " title is required"
105+ }
106+ check(feedItem.markdown.getOrNull() != null ) {
107+ " markdown is required"
108+ }
75109 val key = datastore.newKeyFactory().setKind(KIND_FEED_ITEMS ).newKey()
110+ val now = Clock .System .now()
111+
76112 val entity = Entity .newBuilder(key)!!
77- .set(" title" , feedItem.title)
78- .set(" markdown" , feedItem.markdown)
113+ .set(" title" , feedItem.title.getOrThrow())
114+ .set(" markdown" , feedItem.markdown.getOrThrow())
115+ .set(" createdAt" , now.toString())
79116 .build()
80117
81118 val result = datastore.runInTransaction {
@@ -84,9 +121,10 @@ class RootMutation {
84121
85122 return FeedItemSuccess (
86123 FeedItem (
87- id = result.key.toString(),
88- title = feedItem.title,
89- markdown = feedItem.markdown
124+ id = result.key.id.toString(),
125+ title = result.getString(" title" ),
126+ markdown = result.getString(" markdown" ),
127+ createdAt = result.getString(" createdAt" ).toInstant()
90128 )
91129 )
92130 }
@@ -298,6 +336,7 @@ class RootQuery {
298336
299337 val query = Query .newEntityQueryBuilder()
300338 .setKind(KIND_FEED_ITEMS )
339+ .addOrderBy(StructuredQuery .OrderBy .desc(" createdAt" ))
301340 .setLimit(first)
302341 .apply {
303342 if (after != null ) {
@@ -312,9 +351,10 @@ class RootQuery {
312351 results.forEach { entity ->
313352 allItems.add(
314353 FeedItem (
315- id = entity.key.toString(),
354+ id = entity.key.id. toString(),
316355 title = entity.getString(" title" ),
317- markdown = entity.getString(" markdown" )
356+ markdown = entity.getString(" markdown" ),
357+ createdAt = entity.getString(" createdAt" ).toInstant(),
318358 )
319359 )
320360 }
@@ -333,13 +373,12 @@ class RootQuery {
333373 if (authenticationContext.uid == null ) {
334374 return null
335375 }
336- return User (id = authenticationContext.uid, email = authenticationContext.email !! , isAdmin = authenticationContext.email in adminEmails )
376+ return User (id = authenticationContext.uid, isAdmin = authenticationContext.uid in adminUids )
337377 }
338378}
339379
340380class User (
341381 val id : String ,
342- val email : String ,
343382 val isAdmin : Boolean
344383)
345384
0 commit comments