func (this *ShareService) UpdateShareNotebookPerm(notebookId string, perm int, userId, toUserId string) bool { return db.UpdateByQField(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)}, "Perm", perm, ) }
// URL: /reply/{replyId}/delete // 删除回复,只有管理员可以删除 func deleteReplyHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) replyId := vars["replyId"] user, ok := currentUser(r) if !ok { http.Redirect(w, r, "/signin", http.StatusFound) return } if !user.IsSuperuser { message(w, r, "没用该权限", "对不起,你没有权限删除该回复", "error") return } c := db.C("replies") var reply Reply err := c.Find(bson.M{"_id": bson.ObjectIdHex(replyId)}).One(&reply) if err != nil { message(w, r, "该回复不存在", "不存在该回复", "error") return } err = c.Remove(bson.M{"_id": bson.ObjectIdHex(replyId)}) if err != nil { message(w, r, "该回复不存在", "不存在该回复", "error") return } c = db.C("topics") // 减少该主题的回复数量 c.Update(bson.M{"_id": reply.TopicId}, bson.M{"$inc": bson.M{"replycount": -1}}) var topic Topic c.Find(bson.M{"_id": reply.TopicId}).One(&topic) if topic.LatestReplyId == replyId { if topic.ReplyCount == 0 { // 如果删除后没有回复,设置最后回复id为空,最后回复时间为创建时间 c.Update(bson.M{"_id": topic.Id_}, bson.M{"$set": bson.M{"latestreplyid": "", "latestrepliedat": reply.CreatedAt}}) } else { // 如果删除的是该主题最后一个回复,设置主题的最新回复id,和时间 var latestReply Reply c = db.C("replies") c.Find(bson.M{"topicid": topic.Id_}).Sort("-createdat").Limit(1).One(&latestReply) c = db.C("topics") c.Update(bson.M{"_id": topic.Id_}, bson.M{"$set": bson.M{"latestreplyid": latestReply.Id_.Hex(), "latestrepliedat": latestReply.CreatedAt}}) } } c = db.C("status") var status Status c.Find(nil).One(&status) c.Update(bson.M{"_id": status.Id_}, bson.M{"$inc": bson.M{"replycount": -1}}) http.Redirect(w, r, "/t/"+reply.TopicId.Hex(), http.StatusFound) }
// 得到默认的单个的notes 共享集 // 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit // 可以这样! 到时将零散的共享noteId放在用户基本数据中 // 这里不好排序 func (this *ShareService) ListShareNotes(myUserId, sharedUserId string, pageNumber, pageSize int, sortField string, isAsc bool) []info.ShareNoteWithPerm { skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) shareNotes := []info.ShareNote{} db.ShareNotes. Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}). // Sort(sortFieldR). Skip(skipNum). Limit(pageSize). All(&shareNotes) if len(shareNotes) == 0 { return nil } noteIds := make([]bson.ObjectId, len(shareNotes)) for i, each := range shareNotes { noteIds[i] = each.NoteId } notes := noteService.ListNotesByNoteIds(noteIds) notesMap := make(map[bson.ObjectId]info.Note, len(notes)) for _, each := range notes { notesMap[each.NoteId] = each } // 将shareNotes与notes结合起来 notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes)) for i, each := range shareNotes { notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm} } return notesWithPerm }
// 复制别人的共享笔记给我 // TODO 判断是否共享了给我 func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note { if notebookService.IsMyNotebook(notebookId, myUserId) { note := this.GetNote(noteId, fromUserId) if note.NoteId == "" { return info.Note{} } noteContent := this.GetNoteContent(noteId, fromUserId) // 重新生成noteId note.NoteId = bson.NewObjectId() note.NotebookId = bson.ObjectIdHex(notebookId) note.UserId = bson.ObjectIdHex(myUserId) note.IsTop = false note.IsBlog = false // 别人的可能是blog // content noteContent.NoteId = note.NoteId noteContent.UserId = note.UserId // 添加之 note = this.AddNoteAndContent(note, noteContent, note.UserId) // 更新blog状态 isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, myUserId) note.IsBlog = isBlog return note } return info.Note{} }
// Apart from rule, there are two mandatory field which must come from the UI: "content_id" and "comment_id" func UpdateComment(db *mgo.Database, ev ifaces.Event, rule map[string]interface{}, inp map[string][]string, user_id bson.ObjectId) error { dat, err := extract.New(rule).Extract(inp) if err != nil { return err } basic.DateAndAuthor(rule, dat, user_id, true) ids, err := basic.ExtractIds(inp, []string{"content_id", "comment_id"}) if err != nil { return err } comment_id := bson.ObjectIdHex(ids[1]) q := bson.M{ "_id": bson.ObjectIdHex(ids[0]), "comments.comment_id": comment_id, } upd := bson.M{ "$set": bson.M{ "comments.$": dat, }, } err = db.C("contents").Update(q, upd) if err != nil { return err } return db.C("comments").Remove(m{"_id": comment_id}) }
// updatedUserId是否有修改userId noteId的权限? func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool { // 1. noteId是否被共享了? // 得到该note share的信息 /* UserId bson.ObjectId `bson:"UserId"` ToUserId bson.ObjectId `bson:"ToUserId"` NoteId bson.ObjectId `bson:"NoteId"` Perm int `bson:"Perm"` // 权限, 0只读, 1可修改 */ if !db.Has(db.ShareNotes, bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) { // noteId的notebookId是否被共享了? notebookId := noteService.GetNotebookId(noteId) if notebookId.Hex() == "" { return false } // 判断notebook是否被共享 if !db.Has(db.ShareNotebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) { return false } else { return true } } else { return true } }
// URL: /admin/package_category/{id}/edit // 修改包分类 func adminEditPackageCategoryHandler(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] c := DB.C(PACKAGE_CATEGORIES) var category PackageCategory c.Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&category) form := wtforms.NewForm( wtforms.NewTextField("id", "ID", category.Id, wtforms.Required{}), wtforms.NewTextField("name", "名称", category.Name, wtforms.Required{}), ) if r.Method == "POST" { if !form.Validate(r) { renderTemplate(w, r, "package_category/form.html", ADMIN, map[string]interface{}{"form": form}) return } c.Update(bson.M{"_id": bson.ObjectIdHex(id)}, bson.M{"$set": bson.M{ "id": form.Value("id"), "name": form.Value("name"), }}) http.Redirect(w, r, "/admin/package_categories", http.StatusFound) } renderTemplate(w, r, "package_category/form.html", ADMIN, map[string]interface{}{ "form": form, "isNew": false, }) }
func Photos(w http.ResponseWriter, req *http.Request, ctx *models.Context) error { id := req.URL.Query().Get(":id") if !bson.IsObjectIdHex(id) { return perform_status(w, req, http.StatusNotFound) } var photos []*models.Photo if err := ctx.C(P).Find(bson.M{"user": bson.ObjectIdHex(id), "active": true}).All(&photos); err != nil { return perform_status(w, req, http.StatusNotFound) } user := new(models.User) if err := ctx.C("users").FindId(bson.ObjectIdHex(id)).One(user); err != nil { return perform_status(w, req, http.StatusNotFound) } // find the index of the photo photoId := req.URL.Query().Get(":photo") ctx.Data["index"] = 0 var pIds []bson.ObjectId for i, p := range photos { if p.Id.Hex() == photoId { ctx.Data["index"] = i } pIds = append(pIds, p.Id) } return AJAX("galleria.html").Execute(w, map[string]interface{}{ "photos": photos, "user": user, "hash": models.GenUUID(), "ctx": ctx, }) }
func GetBook(n string) *Book { b := new(Book) switch n { case "MobyDick": b.Id = bson.ObjectIdHex("51e9ad9749a1b71843000001") b.Title = "Moby Dick" b.Body = "Queequeg was a native of Rokovoko, an island far away to the West and South. It is not down in any map; true places never are.\n\nWhen a new-hatched savage running wild about his native woodlands in a grass clout, followed by the nibbling goats, as if he were a green sapling; even then, in Queequeg's ambitious soul, lurked a strong desire to see something more of Christendom than a specimen whaler or two. His father was a High Chief, a King; his uncle a High Priest; and on the maternal side he boasted aunts who were the wives of unconquerable warriors. There was excellent blood in his veins—royal stuff; though sadly vitiated, I fear, by the cannibal propensity he nourished in his untutored youth.\n\nA Sag Harbor ship visited his father's bay, and Queequeg sought a passage to Christian lands. But the ship, having her full complement of seamen, spurned his suit; and not all the King his father's influence could prevail. But Queequeg vowed a vow. Alone in his canoe, he paddled off to a distant strait, which he knew the ship must pass through when she quitted the island. On one side was a coral reef; on the other a low tongue of land, covered with mangrove thickets that grew out into the water. Hiding his canoe, still afloat, among these thickets, with its prow seaward, he sat down in the stern, paddle low in hand; and when the ship was gliding by, like a flash he darted out; gained her side; with one backward dash of his foot capsized and sank his canoe; climbed up the chains; and throwing himself at full length upon the deck, grappled a ring-bolt there, and swore not to let it go, though hacked in pieces.\n\nIn vain the captain threatened to throw him overboard; suspended a cutlass over his naked wrists; Queequeg was the son of a King, and Queequeg budged not. Struck by his desperate dauntlessness, and his wild desire to visit Christendom, the captain at last relented, and told him he might make himself at home. But this fine young savage—this sea Prince of Wales, never saw the Captain's cabin. They put him down among the sailors, and made a whaleman of him. But like Czar Peter content to toil in the shipyards of foreign cities, Queequeg disdained no seeming ignominy, if thereby he might happily gain the power of enlightening his untutored countrymen. For at bottom—so he told me—he was actuated by a profound desire to learn among the Christians, the arts whereby to make his people still happier than they were; and more than that, still better than they were. But, alas! the practices of whalemen soon convinced him that even Christians could be both miserable and wicked; infinitely more so, than all his father's heathens. Arrived at last in old Sag Harbor; and seeing what the sailors did there; and then going on to Nantucket, and seeing how they spent their wages in that place also, poor Queequeg gave it up for lost. Thought he, it's a wicked world in all meridians; I'll die a pagan.\n\nAnd thus an old idolator at heart, he yet lived among these Christians, wore their clothes, and tried to talk their gibberish. Hence the queer ways about him, though now some time from home." b.Tags = []string{"Herman Melville", "Classics"} case "AroundWorld": b.Id = bson.ObjectIdHex("51e9ad9749a1b71843000002") b.Title = "Around the World in 80 Days" b.Body = "\"The owners are myself,\" replied the captain. \"The vessel belongs to me.\"\n\n\"I will freight it for you.\"\n\n\"No.\"\n\n\"I will buy it of you.\"\n\n\"No.\"\n\nPhileas Fogg did not betray the least disappointment; but the situation was a grave one. It was not at New York as at Hong Kong, nor with the captain of the Henrietta as with the captain of the Tankadere. Up to this time money had smoothed away every obstacle. Now money failed.\n\nStill, some means must be found to cross the Atlantic on a boat, unless by balloon—which would have been venturesome, besides not being capable of being put in practice. It seemed that Phileas Fogg had an idea, for he said to the captain, \"Well, will you carry me to Bordeaux?\"\n\n\"No, not if you paid me two hundred dollars.\"" b.Tags = []string{"Jules Verne", "Classics", "Contemporary", "Action", "Adventure", "Suspense", "Fantasy"} case "PrincessMars": b.Id = bson.ObjectIdHex("51e9ae1749a1b71843000004") b.Title = "A Princess of Mars" b.Body = "Tal Hajus arose, and I, half fearing, half anticipating his intentions, hurried to the winding runway which led to the floors below. No one was near to intercept me, and I reached the main floor of the chamber unobserved, taking my station in the shadow of the same column that Tars Tarkas had but just deserted. As I reached the floor Tal Hajus was speaking.\n\n\"Princess of Helium, I might wring a mighty ransom from your people would I but return you to them unharmed, but a thousand times rather would I watch that beautiful face writhe in the agony of torture; it shall be long drawn out, that I promise you; ten days of pleasure were all too short to show the love I harbor for your race. The terrors of your death shall haunt the slumbers of the red men through all the ages to come; they will shudder in the shadows of the night as their fathers tell them of the awful vengeance of the green men; of the power and might and hate and cruelty of Tal Hajus. But before the torture you shall be mine for one short hour, and word of that too shall go forth to Tardos Mors, Jeddak of Helium, your grandfather, that he may grovel upon the ground in the agony of his sorrow. Tomorrow the torture will commence; tonight thou art Tal Hajus'; come!\"\n\nHe sprang down from the platform and grasped her roughly by the arm, but scarcely had he touched her than I leaped between them. My short-sword, sharp and gleaming was in my right hand; I could have plunged it into his putrid heart before he realized that I was upon him; but as I raised my arm to strike I thought of Tars Tarkas, and, with all my rage, with all my hatred, I could not rob him of that sweet moment for which he had lived and hoped all these long, weary years, and so, instead, I swung my good right fist full upon the point of his jaw. Without a sound he slipped to the floor as one dead.\n\nIn the same deathly silence I grasped Dejah Thoris by the hand, and motioning Sola to follow we sped noiselessly from the chamber and to the floor above. Unseen we reached a rear window and with the straps and leather of my trappings I lowered, first Sola and then Dejah Thoris to the ground below. Dropping lightly after them I drew them rapidly around the court in the shadows of the buildings, and thus we returned over the same course I had so recently followed from the distant boundary of the city.\n\nWe finally came upon my thoats in the courtyard where I had left them, and placing the trappings upon them we hastened through the building to the avenue beyond. Mounting, Sola upon one beast, and Dejah Thoris behind me upon the other, we rode from the city of Thark through the hills to the south.\n\nInstead of circling back around the city to the northwest and toward the nearest waterway which lay so short a distance from us, we turned to the northeast and struck out upon the mossy waste across which, for two hundred dangerous and weary miles, lay another main artery leading to Helium." b.Tags = []string{"Edgar Rice Burroughs", "Adventure"} case "EarthsCore": b.Id = bson.ObjectIdHex("51e9ae4949a1b71843000005") b.Title = "At the Earth's Core" b.Body = "With no heavenly guide, it is little wonder that I became confused and lost in the labyrinthine maze of those mighty hills. What, in reality, I did was to pass entirely through them and come out above the valley upon the farther side. I know that I wandered for a long time, until tired and hungry I came upon a small cave in the face of the limestone formation which had taken the place of the granite farther back.\n\nThe cave which took my fancy lay halfway up the precipitous side of a lofty cliff. The way to it was such that I knew no extremely formidable beast could frequent it, nor was it large enough to make a comfortable habitat for any but the smaller mammals or reptiles. Yet it was with the utmost caution that I crawled within its dark interior.\n\nHere I found a rather large chamber, lighted by a narrow cleft in the rock above which let the sunlight filter in in sufficient quantities partially to dispel the utter darkness which I had expected. The cave was entirely empty, nor were there any signs of its having been recently occupied. The opening was comparatively small, so that after considerable effort I was able to lug up a bowlder from the valley below which entirely blocked it.\n\nThen I returned again to the valley for an armful of grasses and on this trip was fortunate enough to knock over an orthopi, the diminutive horse of Pellucidar, a little animal about the size of a fox terrier, which abounds in all parts of the inner world. Thus, with food and bedding I returned to my lair, where after a meal of raw meat, to which I had now become quite accustomed, I dragged the bowlder before the entrance and curled myself upon a bed of grasses—a naked, primeval, cave man, as savagely primitive as my prehistoric progenitors.\n\nI awoke rested but hungry, and pushing the bowlder aside crawled out upon the little rocky shelf which was my front porch. Before me spread a small but beautiful valley, through the center of which a clear and sparkling river wound its way down to an inland sea, the blue waters of which were just visible between the two mountain ranges which embraced this little paradise. The sides of the opposite hills were green with verdure, for a great forest clothed them to the foot of the red and yellow and copper green of the towering crags which formed their summit. The valley itself was carpeted with a luxuriant grass, while here and there patches of wild flowers made great splashes of vivid color against the prevailing green." b.Tags = []string{"Edgar Rice Burroughs", "Adventure", "Action", "Fantasy", "Science Fiction"} case "WarWorlds": b.Id = bson.ObjectIdHex("51e9af2749a1b71843000006") b.Title = "The War of the Worlds Book I" b.Body = "\"Did you see a man in the pit?\" I said; but he made no answer to that. We became silent, and stood watching for a time side by side, deriving, I fancy, a certain comfort in one another's company. Then I shifted my position to a little knoll that gave me the advantage of a yard or more of elevation and when I looked for him presently he was walking towards Woking.\n\nThe sunset faded to twilight before anything further happened. The crowd far away on the left, towards Woking, seemed to grow, and I heard now a faint murmur from it. The little knot of people towards Chobham dispersed. There was scarcely an intimation of movement from the pit.\n\nIt was this, as much as anything, that gave people courage, and I suppose the new arrivals from Woking also helped to restore confidence. At any rate, as the dusk came on a slow, intermittent movement upon the sand pits began, a movement that seemed to gather force as the stillness of the evening about the cylinder remained unbroken. Vertical black figures in twos and threes would advance, stop, watch, and advance again, spreading out as they did so in a thin irregular crescent that promised to enclose the pit in its attenuated horns. I, too, on my side began to move towards the pit.\n\nThen I saw some cabmen and others had walked boldly into the sand pits, and heard the clatter of hoofs and the gride of wheels. I saw a lad trundling off the barrow of apples. And then, within thirty yards of the pit, advancing from the direction of Horsell, I noted a little black knot of men, the foremost of whom was waving a white flag.\n\nThis was the Deputation. There had been a hasty consultation, and since the Martians were evidently, in spite of their repulsive forms, intelligent creatures, it had been resolved to show them, by approaching them with signals, that we too were intelligent." b.Tags = []string{"H. G. Wells", "Science Fiction", "Classics"} } return b }
func (v *V) editContent(typ, id string) (interface{}, error) { uni := v.uni hasid := len(id) > 0 uni.Dat["is_content"] = true var indb interface{} if hasid { uni.Dat["op"] = "update" err := uni.Db.C("contents").Find(m{"_id": bson.ObjectIdHex(id)}).One(&indb) // Ugly. if err != nil { return nil, err } indb = basic.Convert(indb) resolver.ResolveOne(uni.Db, indb, nil) uni.Dat["content"] = indb latest_draft := content_model.GetUpToDateDraft(uni.Db, bson.ObjectIdHex(id), indb.(map[string]interface{})) uni.Dat["latest_draft"] = latest_draft timeline, err := content_model.ContentTimeline(uni.Db, indb.(map[string]interface{})) if err != nil { return nil, err } uni.Dat["timeline"] = timeline } else { uni.Dat["op"] = "insert" } return context.Convert(indb), nil }
// Transforms data from db.Item format into mgo format. func toInternal(val interface{}) interface{} { // TODO: use reflection to target kinds and not just types. switch t := val.(type) { case []db.Id: ids := make([]bson.ObjectId, len(t)) for i, _ := range t { ids[i] = bson.ObjectIdHex(string(t[i])) } return ids case db.Id: return bson.ObjectIdHex(string(t)) case db.Item: for k, _ := range t { t[k] = toInternal(t[k]) } case db.Cond: for k, _ := range t { t[k] = toInternal(t[k]) } case map[string]interface{}: for k, _ := range t { t[k] = toInternal(t[k]) } } return val }
// Called from Front hook. // Find slug value by given key. func FindContent(db *mgo.Database, keys []string, val string) (map[string]interface{}, bool) { query := bson.M{} if len(keys) == 0 { return nil, false } else if len(keys) == 1 { if keys[0] == "_id" && len(val) == 24 { // TODO: check for validity of id. query[keys[0]] = bson.ObjectIdHex(val) } else { query[keys[0]] = val } } else { or := []map[string]interface{}{} for _, v := range keys { if v == "_id" && len(v) == 24 { // TODO: check fir validity of id. or = append(or, map[string]interface{}{v: bson.ObjectIdHex(val)}) } else { or = append(or, map[string]interface{}{v: val}) } } query["$or"] = or } var v interface{} db.C(Cname).Find(query).One(&v) if v == nil { return nil, false } return basic.Convert(v).(map[string]interface{}), true }
// Transforms data from db.Item format into mgo format. func toInternal(val interface{}) interface{} { switch val.(type) { case []db.Id: ids := make([]bson.ObjectId, len(val.([]db.Id))) for i, _ := range val.([]db.Id) { ids[i] = bson.ObjectIdHex(string(val.([]db.Id)[i])) } return ids case db.Id: return bson.ObjectIdHex(string(val.(db.Id))) case db.Item: for k, _ := range val.(db.Item) { val.(db.Item)[k] = toInternal(val.(db.Item)[k]) } case db.Cond: for k, _ := range val.(db.Cond) { val.(db.Cond)[k] = toInternal(val.(db.Cond)[k]) } case map[string]interface{}: for k, _ := range val.(map[string]interface{}) { val.(map[string]interface{})[k] = toInternal(val.(map[string]interface{})[k]) } } return val }
// URL: /p/{packageId}/delete // 删除第三方包 func deletePackageHandler(w http.ResponseWriter, r *http.Request) { user, ok := currentUser(r) if !ok { return } if !user.IsSuperuser { return } vars := mux.Vars(r) packageId := vars["packageId"] c := DB.C("contents") package_ := Package{} err := c.Find(bson.M{"_id": bson.ObjectIdHex(packageId), "content.type": TypePackage}).One(&package_) if err != nil { return } c.Remove(bson.M{"_id": bson.ObjectIdHex(packageId)}) // 修改分类下的数量 c = DB.C("packagecategories") c.Update(bson.M{"_id": package_.CategoryId}, bson.M{"$inc": bson.M{"packagecount": -1}}) http.Redirect(w, r, "/packages", http.StatusFound) }
func Test_LoginCheckHandler(t *testing.T) { tmp := &db.Session{UId: bson.ObjectIdHex("52a4ed348350a921bd000001")} db.AddTemp("sessions", tmp) tmpU := &db.User{Id: tmp.UId, OrgId: bson.ObjectIdHex("52a4ed348350a921bd000002"), Email: "a", Password: "******"} db.AddTemp("users", tmpU) msg := &Message{ msg: `{"type":"loginCheck","data":{ "session_id": "` + tmp.Id.Hex() + `" }}`, c: &Connection{owner: &User{}}, } err, _ := HandleMsg(msg) cmd := GetLastCmd() test.Assert(cmd.Data["status"].(string) == "OK", "it recognises the previous session", t) db.DelTemps("sessions") db.DelTemps("users") HandleMsg(msg) cmd = GetLastCmd() test.Assert(cmd.Data["status"].(string) == "UNAUTHORIZED", "it does not authorise user when there is no previous session", t) msg.msg = `{"type":"loginCheck","data":{"session_id": "invalid"}}` err, _ = HandleMsg(msg) test.Assert(err != nil, "It returns an error if session id is invalid objectid", t) msg.msg = `{"type":"loginCheck","data":{"session_id": 5}}` err, _ = HandleMsg(msg) test.Assert(err != nil, "It returns an error if session id is invalid string", t) }
// URL: /p/{packageId}/delete // 删除第三方包 func deletePackageHandler(handler Handler) { vars := mux.Vars(handler.Request) packageId := vars["packageId"] if !bson.IsObjectIdHex(packageId) { http.NotFound(handler.ResponseWriter, handler.Request) return } c := DB.C(CONTENTS) package_ := Package{} err := c.Find(bson.M{"_id": bson.ObjectIdHex(packageId), "content.type": TypePackage}).One(&package_) if err != nil { return } c.Remove(bson.M{"_id": bson.ObjectIdHex(packageId)}) // 修改分类下的数量 c = DB.C(PACKAGE_CATEGORIES) c.Update(bson.M{"_id": package_.CategoryId}, bson.M{"$inc": bson.M{"packagecount": -1}}) http.Redirect(handler.ResponseWriter, handler.Request, "/packages", http.StatusFound) }
/*mark ggaaooppeenngg*/ func (u *Utils) RecentReplies(username string) template.HTML { c := DB.C(USERS) ccontens := DB.C(CONTENTS) user := User{} // 检查用户名 c.Find(bson.M{"username": username}).One(&user) var anchors []string anchor := `<a href="/t/%s" class="btn">%s</a><br>` for _, v := range user.RecentReplies { var topic Topic err := ccontens.Find(bson.M{"_id": bson.ObjectIdHex(v)}).One(&topic) if err != nil { fmt.Println(err) } anchors = append(anchors, fmt.Sprintf(anchor, topic.Id_.Hex(), topic.Title)) } s := strings.Join(anchors, "\n") //最近被at var ats []string for _, v := range user.RecentAts { var topic Topic if err := ccontens.Find(bson.M{"_id": bson.ObjectIdHex(v)}).One(&topic); err != nil { fmt.Println(err) } ats = append(ats, fmt.Sprintf(anchor, topic.Id_.Hex(), topic.Title)) } a := strings.Join(ats, "\n") tpl := `<h4><small>最近回复</small></h4> <hr> ` + s + `<h4><small>被at</small></h4> <hr> ` + a return template.HTML(tpl) }
func CommentForm(w http.ResponseWriter, req *http.Request, ctx *models.Context) error { //set up the collection and query id := req.URL.Query().Get(":id") kind := req.URL.Query().Get(":kind") if !bson.IsObjectIdHex(id) { return perform_status(w, req, http.StatusForbidden) } var object models.Commenter switch kind { case "p": query := ctx.C(P).FindId(bson.ObjectIdHex(id)) //execute the query photo := &models.Photo{} if err := query.One(&photo); err != nil { return perform_status(w, req, http.StatusNotFound) } object = photo case "c": query := ctx.C(C).FindId(bson.ObjectIdHex(id)) //execute the query contest := &models.Contest{} if err := query.One(&contest); err != nil { return perform_status(w, req, http.StatusNotFound) } object = contest } //execute the template return AJAX("comments.html").Execute(w, map[string]interface{}{ "object": object, "kind": kind, "ctx": ctx, }) }
// list images // if albumId == "" get default album images func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNumber, pageSize int) info.Page { skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false) files := []info.File{} q := bson.M{"UserId": bson.ObjectIdHex(userId)} if albumId != "" { q["AlbumId"] = bson.ObjectIdHex(albumId) } else { q["IsDefaultAlbum"] = true } if key != "" { q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}} } // LogJ(q) count := db.Count(db.Files, q) db.Files. Find(q). Sort(sortFieldR). Skip(skipNum). Limit(pageSize). All(&files) return info.Page{Count: count, List: files} }
// 更新notebook func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool { needUpdate["UpdatedTime"] = time.Now() // 如果有IsBlog之类的, 需要特殊处理 if isBlog, ok := needUpdate["IsBlog"]; ok { // 设为blog/取消 if is, ok2 := isBlog.(bool); ok2 { q := bson.M{"UserId": bson.ObjectIdHex(userId), "NotebookId": bson.ObjectIdHex(notebookId)} db.UpdateByQMap(db.Notes, q, bson.M{"IsBlog": is}) // noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId // 先查该notebook下所有notes, 得到id notes := []info.Note{} db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es) if len(notes) > 0 { noteIds := make([]bson.ObjectId, len(notes)) for i, each := range notes { noteIds[i] = each.NoteId } db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog}) } } } return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate) }
func txPagingFunc(c *mgo.Collection, first, last string, args ...interface{}) (query bson.M, err error) { tx := &Tx{} if bson.IsObjectIdHex(first) { if err := c.FindId(bson.ObjectIdHex(first)).One(tx); err != nil { return nil, err } query = bson.M{ "time": bson.M{ "$gte": tx.Time, }, } } else if bson.IsObjectIdHex(last) { if err := c.FindId(bson.ObjectIdHex(last)).One(tx); err != nil { return nil, err } query = bson.M{ "time": bson.M{ "$lte": tx.Time, }, } } return }
func recordPagingFunc(c *mgo.Collection, first, last string, args ...interface{}) (query bson.M, err error) { record := &Record{} if bson.IsObjectIdHex(first) { if err := c.FindId(bson.ObjectIdHex(first)).One(record); err != nil { return nil, err } query = bson.M{ "starttime": bson.M{ "$gte": record.PubTime, }, } } else if bson.IsObjectIdHex(last) { if err := c.FindId(bson.ObjectIdHex(last)).One(record); err != nil { return nil, err } query = bson.M{ "starttime": bson.M{ "$lte": record.PubTime, }, } } return }
func (c *Context) Vote(voterId, pollId string, choiceId uint) error { // Find the voter and check if they already voted in this poll voterCursor := c.mgoSession.DB("pollr").C("voters") voter := Voter{} findVoterErr := voterCursor.FindId(bson.ObjectIdHex(voterId)).One(&voter) if findVoterErr != nil { log.Printf("Couldn't find voter %v", voterId) return findVoterErr } if _, ok := voter.Votes[pollId]; ok { log.Printf("Voter %v already voted!", voterId) return nil } // Update the poll with the new vote, record the users vote, and publish the vote to redis poll := bson.ObjectIdHex(pollId) cursor := c.mgoSession.DB("pollr").C("polls") err := cursor.UpdateId(poll, bson.M{"$inc": bson.M{fmt.Sprintf("choices.%v.votes", choiceId): 1}}) if err != nil { log.Printf("Couldn't cast vote for poll %s choice %v", poll.Hex(), choiceId) return err } voter.Votes[pollId] = choiceId voterCursor.UpdateId(bson.ObjectIdHex(voterId), voter) go c.publish(fmt.Sprintf("polls:%s", pollId), choiceId) return nil }
func articlePagingFunc(c *mgo.Collection, first, last string, args ...interface{}) (query bson.M, err error) { article := &Article{} if bson.IsObjectIdHex(first) { if err := c.FindId(bson.ObjectIdHex(first)).One(article); err != nil { return nil, err } query = bson.M{ "pub_time": bson.M{ "$gte": article.PubTime, }, } } else if bson.IsObjectIdHex(last) { if err := c.FindId(bson.ObjectIdHex(last)).One(article); err != nil { return nil, err } query = bson.M{ "pub_time": bson.M{ "$lte": article.PubTime, }, } } return }
func (this *RootArticleRouter) Post() { id := this.GetString("id") if len(this.Input()) == 1 { //删除操作 models.DeleteArticle(&bson.M{"_id": bson.ObjectIdHex(id)}) this.Data["json"] = true this.ServeJson(true) } else { nodename := this.GetString("selectnode") name := this.GetString("name") title := this.GetString("title") content := this.GetString("content") isThumbnail, _ := this.GetBool("isThumbnail") featuredPicURL := this.GetString("featuredPicURL") tags := this.GetStrings("tags") author, _ := this.GetSession("username").(string) cat := models.GetCategoryNodeName(nodename) if name == "" { name = strconv.Itoa(int(bson.Now().UnixNano())) } if id != "" { //更新 article, _ := models.GetArticle(&bson.M{"_id": bson.ObjectIdHex(id)}) article.CName = cat.Name article.NName = nodename article.Name = name article.Author = author article.Title = title article.Tags = tags article.FeaturedPicURL = featuredPicURL article.ModifiedTime = bson.Now() article.Text = template.HTML(content) article.IsThumbnail = isThumbnail article.SetSummary() article.UpdateArticle() this.Redirect("/root/article", 302) } else { //创建 article := models.Article{ CName: cat.Name, NName: nodename, Name: name, Author: author, Title: title, Tags: tags, FeaturedPicURL: featuredPicURL, CreatedTime: bson.Now(), ModifiedTime: bson.Now(), Text: template.HTML(content), IsThumbnail: isThumbnail, } article.SetSummary() article.CreatArticle() go Publish(&article) this.Redirect("/root/article", 302) } } }
// delete album // presupposition: has no images under this ablum func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) { if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId), "UserId": bson.ObjectIdHex(userId), }) == 0 { return db.DeleteByIdAndUserId(db.Albums, albumId, userId), "" } return false, "has images" }
// 先查看该notebookId下是否有notes, 没有则删除 func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) { if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "IsTrash": false}) == 0 { // 不包含trash return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), "" } return false, "笔记本下有笔记" }
// 删除userId分享给toUserId的所有 func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool { query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)} db.DeleteAll(db.ShareNotebooks, query) db.DeleteAll(db.ShareNotes, query) db.DeleteAll(db.HasShareNotes, query) return true }
// URL: /comment/{contentId} // 评论,不同内容共用一个评论方法 func commentHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { return } user, _ := currentUser(r) vars := mux.Vars(r) contentId := vars["contentId"] var temp map[string]interface{} c := DB.C("contents") c.Find(bson.M{"_id": bson.ObjectIdHex(contentId)}).One(&temp) temp2 := temp["content"].(map[string]interface{}) type_ := temp2["type"].(int) var url string switch type_ { case TypeArticle: url = "/a/" + contentId case TypeTopic: url = "/t/" + contentId case TypePackage: url = "/p/" + contentId } c.Update(bson.M{"_id": bson.ObjectIdHex(contentId)}, bson.M{"$inc": bson.M{"content.commentcount": 1}}) content := r.FormValue("content") html := r.FormValue("html") html = strings.Replace(html, "<pre>", `<pre class="prettyprint linenums">`, -1) Id_ := bson.NewObjectId() now := time.Now() c = DB.C("comments") c.Insert(&Comment{ Id_: Id_, Type: type_, ContentId: bson.ObjectIdHex(contentId), Markdown: content, Html: template.HTML(html), CreatedBy: user.Id_, CreatedAt: now, }) if type_ == TypeTopic { // 修改最后回复用户Id和时间 c = DB.C("contents") c.Update(bson.M{"_id": bson.ObjectIdHex(contentId)}, bson.M{"$set": bson.M{"latestreplierid": user.Id_.Hex(), "latestrepliedat": now}}) } http.Redirect(w, r, url, http.StatusFound) }
// 新建历史 func (this *NoteContentHistoryService) newHistory(noteId, userId string, eachHistory info.EachHistory) { history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId), UserId: bson.ObjectIdHex(userId), Histories: []info.EachHistory{eachHistory}, } // 保存之 db.Insert(db.NoteContentHistories, history) }