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
-
7models/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