Browse Source
models, graph2: Added Comment type and queries, and hooked it up to chapter.
module-madness-pointers
models, graph2: Added Comment type and queries, and hooked it up to chapter.
module-madness-pointers
Gisle Aune
6 years ago
14 changed files with 306 additions and 8 deletions
-
4graph2/gqlgen.yml
-
4graph2/graph.go
-
15graph2/queries/comment.go
-
4graph2/schema/root.gql
-
29graph2/schema/types/Chapter.gql
-
31graph2/schema/types/Comment.gql
-
15graph2/types/chapter.go
-
27graph2/types/comment.go
-
57models/chapter-comment-mode.go
-
23models/chapter.go
-
17models/comment.go
-
66models/comments/db.go
-
11models/comments/find.go
-
11models/comments/list.go
@ -0,0 +1,15 @@ |
|||
package queries |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/rpdata/api/models/comments" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
) |
|||
|
|||
// Queries
|
|||
|
|||
func (r *resolver) Comment(ctx context.Context, id string) (models.Comment, error) { |
|||
return comments.Find(id) |
|||
} |
@ -0,0 +1,31 @@ |
|||
""" |
|||
A Comment represents a comment to a story chapter. |
|||
""" |
|||
type Comment { |
|||
"A unique ID of the change." |
|||
id: String! |
|||
|
|||
"subject" |
|||
subject: String! |
|||
|
|||
"The comment's author." |
|||
author: String! |
|||
|
|||
"The displayed name of the character. This may be the same as character.name, but it does not need to be." |
|||
characterName: String! |
|||
|
|||
"The character associated with the comment." |
|||
character: Character |
|||
|
|||
"The fictional (IC) date of the comment." |
|||
fictionalDate: Date |
|||
|
|||
"The date of creation." |
|||
createdDate: Date! |
|||
|
|||
"The date of the last edit." |
|||
editedDate: Date! |
|||
|
|||
"The markdown source of the comment." |
|||
source: String! |
|||
} |
@ -0,0 +1,27 @@ |
|||
package types |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/rpdata/api/models/characters" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
) |
|||
|
|||
type commentResolver struct{} |
|||
|
|||
func (r *commentResolver) Character(ctx context.Context, obj *models.Comment) (*models.Character, error) { |
|||
if obj.CharacterID == "" { |
|||
return nil, nil |
|||
} |
|||
|
|||
character, err := characters.FindID(obj.CharacterID) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &character, nil |
|||
} |
|||
|
|||
// CommentResolver is a resolver
|
|||
var CommentResolver commentResolver |
@ -0,0 +1,57 @@ |
|||
package models |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io" |
|||
) |
|||
|
|||
// ChapterCommentMode represents the kind of tags.
|
|||
type ChapterCommentMode string |
|||
|
|||
const ( |
|||
// ChapterCommentModeDisabled is a chapter comment mode, see GraphQL documentation.
|
|||
ChapterCommentModeDisabled ChapterCommentMode = "Disabled" |
|||
|
|||
// ChapterCommentModeArticle is a chapter comment mode, see GraphQL documentation.
|
|||
ChapterCommentModeArticle ChapterCommentMode = "Article" |
|||
|
|||
// ChapterCommentModeChat is a chapter comment mode, see GraphQL documentation.
|
|||
ChapterCommentModeChat ChapterCommentMode = "Chat" |
|||
|
|||
// ChapterCommentModeMessage is a chapter comment mode, see GraphQL documentation.
|
|||
ChapterCommentModeMessage ChapterCommentMode = "Message" |
|||
) |
|||
|
|||
// UnmarshalGQL unmarshals
|
|||
func (e *ChapterCommentMode) UnmarshalGQL(v interface{}) error { |
|||
str, ok := v.(string) |
|||
if !ok { |
|||
return fmt.Errorf("enums must be strings") |
|||
} |
|||
|
|||
*e = ChapterCommentMode(str) |
|||
switch *e { |
|||
case ChapterCommentModeDisabled, ChapterCommentModeArticle, ChapterCommentModeChat, ChapterCommentModeMessage: |
|||
return nil |
|||
default: |
|||
return fmt.Errorf("%s is not a valid ChapterCommentMode", str) |
|||
} |
|||
} |
|||
|
|||
// IsEnabled returns true if comments are enabled.
|
|||
func (e ChapterCommentMode) IsEnabled() bool { |
|||
return e != ChapterCommentModeDisabled && len(e) != 0 |
|||
} |
|||
|
|||
// MarshalGQL turns it into a JSON string
|
|||
func (e ChapterCommentMode) MarshalGQL(w io.Writer) { |
|||
// Backwards compatibility: Empty value means disabled.
|
|||
if len(e) == 0 { |
|||
w.Write(disabledChapterCommentModeBytes) |
|||
return |
|||
} |
|||
|
|||
fmt.Fprint(w, "\""+string(e)+"\"") |
|||
} |
|||
|
|||
var disabledChapterCommentModeBytes = []byte(`"Disabled"`) |
@ -0,0 +1,17 @@ |
|||
package models |
|||
|
|||
import "time" |
|||
|
|||
// A Comment is a comment on a chapter.
|
|||
type Comment struct { |
|||
ID string `bson:"id"` |
|||
ChapterID string `bson:"chapterId"` |
|||
Subject string `bson:"subject"` |
|||
Author string `bson:"author"` |
|||
CharacterName string `bson:"characterName"` |
|||
CharacterID string `bson:"characterId"` |
|||
FictionalDate time.Time `bson:"fictionalDate"` |
|||
CreatedDate time.Time `bson:"createdDate"` |
|||
EditedDate time.Time `bson:"editeddDate"` |
|||
Source string `bson:"sources"` |
|||
} |
@ -0,0 +1,66 @@ |
|||
package comments |
|||
|
|||
import ( |
|||
"crypto/rand" |
|||
"encoding/binary" |
|||
"strconv" |
|||
|
|||
"git.aiterp.net/rpdata/api/internal/store" |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo" |
|||
) |
|||
|
|||
var collection *mgo.Collection |
|||
|
|||
func find(query interface{}) (models.Comment, error) { |
|||
comment := models.Comment{} |
|||
err := collection.Find(query).One(&comment) |
|||
|
|||
return comment, err |
|||
} |
|||
|
|||
func list(query interface{}, limit int) ([]models.Comment, error) { |
|||
allocSize := 32 |
|||
if limit >= 0 { |
|||
allocSize = limit |
|||
} else { |
|||
limit = 0 |
|||
} |
|||
|
|||
comments := make([]models.Comment, 0, allocSize) |
|||
err := collection.Find(query).Sort("createdDate").Limit(limit).All(&comments) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return comments, nil |
|||
} |
|||
|
|||
func makeCommentID() string { |
|||
result := "SCC" |
|||
offset := 0 |
|||
data := make([]byte, 48) |
|||
|
|||
rand.Read(data) |
|||
for len(result) < 32 { |
|||
result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36) |
|||
offset += 8 |
|||
|
|||
if offset >= 48 { |
|||
rand.Read(data) |
|||
offset = 0 |
|||
} |
|||
} |
|||
|
|||
return result[:32] |
|||
} |
|||
|
|||
func init() { |
|||
store.HandleInit(func(db *mgo.Database) { |
|||
collection = db.C("story.comments") |
|||
|
|||
collection.EnsureIndexKey("chapterId") |
|||
collection.EnsureIndexKey("author") |
|||
collection.EnsureIndexKey("createdDate") |
|||
}) |
|||
} |
@ -0,0 +1,11 @@ |
|||
package comments |
|||
|
|||
import ( |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo/bson" |
|||
) |
|||
|
|||
// Find finds a comment by ID.
|
|||
func Find(id string) (models.Comment, error) { |
|||
return find(bson.M{"_id": id}) |
|||
} |
@ -0,0 +1,11 @@ |
|||
package comments |
|||
|
|||
import ( |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo/bson" |
|||
) |
|||
|
|||
// ListChapterID lists all comments by chapter-ID
|
|||
func ListChapterID(chapterID string, limit int) ([]models.Comment, error) { |
|||
return list(bson.M{"chapterId": chapterID}, limit) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue