github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/models/node.go (about) 1 package models 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "os" 8 "strconv" 9 "time" 10 "github.com/insionng/yougam/helper" 11 ) 12 13 type Node struct { 14 Id int64 15 Pid int64 `xorm:"index"` //pid为0 代表节点本身是顶层节点, pid大于0 代表上级节点id , 编写逻辑的时候注意判断此pid不能等于自身id 16 Cid int64 `xorm:"index"` //所属分类的id 17 Uid int64 `xorm:"index"` 18 Sort int64 19 Ctype int64 `xorm:"index"` 20 Title string `xorm:"index"` 21 Content string `xorm:"text"` 22 Attachment string `xorm:"text"` 23 Created int64 `xorm:"created index"` 24 Updated int64 `xorm:"updated"` 25 Hotness float64 `xorm:"index"` 26 Confidence float64 `xorm:"index"` //信任度数值 27 Hotup int64 `xorm:"index"` 28 Hotdown int64 `xorm:"index"` 29 Hotscore int64 `xorm:"index"` //Hotup - Hotdown 30 Hotvote int64 `xorm:"index"` //Hotup + Hotdown 31 Views int64 32 Author string `xorm:"index"` //节点的创建者 33 Parent string `xorm:"index"` //父级节点名称 34 Category string `xorm:"index"` //所属分类标题 35 Tid int64 //最后一次发布的topic的Tid 36 Topic int64 //最后一次发布的topic的标题 37 TopicTime int64 38 TopicCount int64 39 TopicLastUserId int64 40 FavoriteCount int64 `xorm:"index"` 41 Template string `xorm:"index"` 42 } 43 44 type NodeMark struct { 45 Id int64 46 Uid int64 `xorm:"index"` 47 Nid int64 `xorm:"index"` //node id 48 } 49 50 type NodeBookmark struct { 51 Id int64 52 Userid int64 `xorm:"index"` 53 Nodeid int64 `xorm:"index"` 54 } 55 56 func HasNode(title string) (int64, bool) { 57 58 nd := new(Node) 59 if has, err := Engine.Where("title = ?", title).Get(nd); err != nil { 60 return -1, false 61 } else { 62 if has { 63 return nd.Id, true 64 } 65 return -1, false 66 } 67 } 68 69 //返回所有存在的节点 70 func AllExistingNodes(offset int, limit int, field string) (*[]*Node, error) { 71 nds := new([]*Node) 72 err := Engine.Where("cid>=?", -2).Limit(limit, offset).Desc(field).Find(nds) 73 return nds, err 74 } 75 76 func AvailableNodes(offset int, limit int, field string) (*[]*Node, error) { 77 nds := new([]*Node) 78 err := Engine.Where("cid>=?", -1).Limit(limit, offset).Desc(field).Find(nds) 79 return nds, err 80 } 81 82 func NodesOfNodes(offset int, limit int, field string) (*[]*Node, error) { 83 nds := new([]*Node) 84 err := Engine.Where("cid>?", 0).Limit(limit, offset).Desc(field).Find(nds) 85 return nds, err 86 } 87 88 func NodesOfNavor(offset int, limit int, field string) (*[]*Node, error) { 89 nds := new([]*Node) 90 err := Engine.Where("cid<=? and cid>=?", 0, -1).Limit(limit, offset).Desc(field).Find(nds) 91 return nds, err 92 } 93 94 func SetNodeMark(uid int64, nid int64) (int64, error) { 95 nm := new(NodeMark) 96 nm = &NodeMark{Uid: uid, Nid: nid} 97 rows, err := Engine.Insert(nm) 98 return rows, err 99 } 100 101 func IsNodeMark(uid int64, nid int64) bool { 102 103 nm := new(NodeMark) 104 105 if has, err := Engine.Where("uid=? and nid=?", uid, nid).Get(nm); err != nil { 106 return false 107 } else { 108 if has { 109 if nm.Uid == uid { 110 return true 111 } else { 112 return false 113 } 114 115 } else { 116 return false 117 } 118 } 119 120 } 121 122 func GetNodesViaPid(pid int64, offset int, limit int, ctype int64, field string) *[]*Node { 123 var objs = new([]*Node) 124 if pid <= 0 { 125 switch { 126 case field == "asc": 127 { 128 if ctype != 0 { 129 Engine.Where("pid <= ? and ctype = ?", 0, ctype).Limit(limit, offset).Asc("id").Find(objs) 130 } else { 131 Engine.Where("pid <= ?", 0).Limit(limit, offset).Asc("id").Find(objs) 132 } 133 } 134 default: 135 { 136 if ctype != 0 { 137 Engine.Where("pid <= ? and ctype = ?", 0, ctype).Limit(limit, offset).Desc(field).Find(objs) 138 } else { 139 Engine.Where("pid <= ?", 0).Limit(limit, offset).Desc(field).Find(objs) 140 } 141 } 142 } 143 } else { 144 switch { 145 case field == "asc": 146 { 147 if ctype != 0 { 148 Engine.Where("pid=? and ctype=?", pid, ctype).Limit(limit, offset).Asc("id").Find(objs) 149 } else { 150 Engine.Where("pid=?", pid).Limit(limit, offset).Asc("id").Find(objs) 151 } 152 } 153 default: 154 { 155 if ctype != 0 { 156 Engine.Where("pid=? and ctype=?", pid, ctype).Limit(limit, offset).Desc(field).Find(objs) 157 } else { 158 Engine.Where("pid=?", pid).Limit(limit, offset).Desc(field).Find(objs) 159 } 160 } 161 } 162 } 163 return objs 164 } 165 166 func GetNodesByCtypeWithNid(offset int, limit int, ctype int64, nid int64, field string) (*[]*Node, error) { 167 objs := new([]*Node) 168 err := Engine.Table("node").Where("ctype = ? and nid = ?", ctype, nid).Limit(limit, offset).Desc(field).Find(objs) 169 return objs, err 170 } 171 172 func GetNodesByCtype(offset int, limit int, ctype int64, field string) (*[]*Node, error) { 173 catz := new([]*Node) 174 err := Engine.Table("node").Where("ctype = ?", ctype).Limit(limit, offset).Desc(field).Find(catz) 175 return catz, err 176 } 177 178 /* 179 func GetNodesByCid(cid int64, offset int, limit int, field string) (*[]*Node, error) { 180 nds := new([]*Node) 181 err := Engine.Where("cid=?", cid).Limit(limit, offset).Desc(field).Find(nds) 182 return nds, err 183 } 184 */ 185 func GetNodesByCid(cid int64, offset int, limit int, field string) (*[]*Node, error) { 186 nds := new([]*Node) 187 var err error 188 if cid != 0 { 189 /* 190 if cid == -2 { //cid为-2时节点对前端隐藏展示 191 err = Engine.Where("cid>?", cid).Limit(limit, offset).Desc(field).Find(nds) 192 } else { 193 err = Engine.Where("cid=?", cid).Limit(limit, offset).Desc(field).Find(nds) 194 } 195 */ 196 err = Engine.Where("cid=?", cid).Limit(limit, offset).Desc(field).Find(nds) 197 198 } else { 199 err = Engine.Limit(limit, offset).Desc(field).Find(nds) 200 } 201 return nds, err 202 } 203 204 func GetNodesByCtypeWithPid(offset int, limit int, ctype int64, pid int64, field string) (*[]*Node, error) { 205 catz := new([]*Node) 206 err := Engine.Table("node").Where("ctype = ? and pid = ?", ctype, pid).Limit(limit, offset).Desc(field).Find(catz) 207 return catz, err 208 } 209 210 func AddNode(title string, content string, attachment string, nid int64, cid int64, uid int64) (int64, error) { 211 212 nd := &Node{Pid: nid, Cid: cid, Uid: uid, Title: title, Content: content, Attachment: attachment, Created: time.Now().Unix()} 213 if _, err := Engine.Insert(nd); err == nil { 214 return nd.Id, err 215 } else { 216 return -1, err 217 } 218 219 } 220 221 func SetNode(nid int64, nd *Node) (int64, error) { 222 nd.Id = nid 223 return Engine.Insert(nd) 224 } 225 226 func GetNode(id int64) (*Node, error) { 227 228 nd := &Node{} 229 has, err := Engine.Id(id).Get(nd) 230 if has { 231 return nd, err 232 } else { 233 234 return nil, err 235 } 236 237 } 238 239 func GetNodeByTitle(title string) (*Node, error) { 240 nd := &Node{} 241 nd.Title = title 242 has, err := Engine.Get(nd) 243 if has { 244 return nd, err 245 } else { 246 247 return nil, err 248 } 249 } 250 251 func GetNodesByCtypeWithCid(offset int, limit int, ctype int64, cid int64, field string) (*[]*Node, error) { 252 catz := new([]*Node) 253 err := Engine.Table("node").Where("ctype = ? and cid = ?", ctype, cid).Limit(limit, offset).Desc(field).Find(catz) 254 return catz, err 255 } 256 257 func GetNodesByPid(pid int64, offset int, limit int, ctype int64, field string) *[]*Node { 258 259 nds := new([]*Node) 260 261 switch { 262 case field == "asc": 263 { 264 if ctype != 0 { 265 Engine.Where("(pid=? or id=?) and ctype=?", pid, pid, ctype).Limit(limit, offset).Asc("id").Find(nds) 266 } else { 267 Engine.Where("pid=? or id=?", pid, pid).Limit(limit, offset).Asc("id").Find(nds) 268 } 269 } 270 default: 271 { 272 if ctype != 0 { 273 Engine.Where("(pid=? or id=?) and ctype=?", pid, pid, ctype).Limit(limit, offset).Desc(field).Find(nds) 274 } else { 275 Engine.Where("pid=? or id=?", pid, pid).Limit(limit, offset).Desc(field).Find(nds) 276 } 277 } 278 } 279 return nds 280 } 281 282 func GetNodes(offset int, limit int, field string) (*[]*Node, error) { 283 nds := new([]*Node) 284 err := Engine.Limit(limit, offset).Desc(field).Find(nds) 285 return nds, err 286 } 287 288 func PutNode(nid int64, nd *Node) (int64, error) { 289 //覆盖式更新 290 sess := Engine.NewSession() 291 defer sess.Close() 292 // 启动事务 293 if err := sess.Begin(); err != nil { 294 return -1, err 295 } 296 297 //执行事务 298 nodeid := int64(0) 299 if row, err := sess.Update(nd, &Node{Id: nid}); err != nil || row <= 0 { 300 sess.Rollback() 301 return -1, err 302 } else { 303 if nd.Uid > 0 { 304 n, _ := sess.Where("uid=?", nd.Uid).Count(&Node{}) 305 _u := map[string]interface{}{"node_time": time.Now().Unix(), "node_count": n, "node_last_tid": nd.Tid, "node_last_topic": nd.Topic} 306 if row, err := sess.Table(&User{}).Where("id=?", nd.Uid).Update(&_u); err != nil || row <= 0 { 307 sess.Rollback() 308 return -1, errors.New(fmt.Sprint("PutNode更新user表话题相关信息时,执行:", row, "行变更,出现错误:", err)) 309 } 310 } 311 312 nodeid = nd.Id 313 } 314 315 // 提交事务 316 return nodeid, sess.Commit() 317 } 318 319 //map[string]interface{}{"ctype": ctype} 320 func UpdateNode(nid int64, nodemap *map[string]interface{}) error { 321 nd := &Node{} 322 if row, err := Engine.Table(nd).Where("id=?", nid).Update(nodemap); err != nil || row == 0 { 323 log.Println("UpdateNode row:::", row, "UpdateNode出现错误:", err) 324 return err 325 } else { 326 return nil 327 } 328 329 } 330 331 func DelNode(id int64, uid int64, role int64) error { 332 allow := false 333 if role < 0 { 334 allow = true 335 } 336 337 node := &Node{} 338 339 if has, err := Engine.Id(id).Get(node); has == true && err == nil { 340 341 if node.Uid == uid || allow { 342 //检查附件字段并尝试删除文件 343 if len(node.Attachment) > 0 { 344 345 if p := helper.URL2local(node.Attachment); helper.Exist(p) { 346 //验证是否管理员权限 347 if allow { 348 if err := os.Remove(p); err != nil { 349 //可以输出错误日志,但不要反回错误,以免陷入死循环无法删掉 350 fmt.Println("ROOT DEL NODE Attachment, NODE ID:", id, ",ERR:", err) 351 } 352 } else { //检查用户对本地文件的所有权 353 if helper.VerifyUserfile(p, strconv.FormatInt(uid, 10)) { 354 if err := os.Remove(p); err != nil { 355 fmt.Println("DEL NODE Attachment, NODE ID:", id, ",ERR:", err) 356 } 357 } 358 } 359 360 } 361 } 362 363 //检查内容字段并尝试删除文件 364 if len(node.Content) > 0 { 365 //若内容中存在图片则开始尝试删除图片 366 delfiles_local := []string{} 367 368 if m, n := helper.GetImages(node.Content); n > 0 { 369 370 for _, v := range m { 371 if helper.IsLocal(v) { 372 delfiles_local = append(delfiles_local, v) 373 //如果本地同时也存在banner缓存文件,则加入旧图集合中,等待后面一次性删除 374 if p := helper.URL2local(helper.SetSuffix(v, "_banner.jpg")); helper.Exist(p) { 375 delfiles_local = append(delfiles_local, p) 376 } 377 if p := helper.URL2local(helper.SetSuffix(v, "_large.jpg")); helper.Exist(p) { 378 delfiles_local = append(delfiles_local, p) 379 } 380 if p := helper.URL2local(helper.SetSuffix(v, "_medium.jpg")); helper.Exist(p) { 381 delfiles_local = append(delfiles_local, p) 382 } 383 if p := helper.URL2local(helper.SetSuffix(v, "_small.jpg")); helper.Exist(p) { 384 delfiles_local = append(delfiles_local, p) 385 } 386 } 387 } 388 for k, v := range delfiles_local { 389 if p := helper.URL2local(v); helper.Exist(p) { //如若文件存在,则处理,否则忽略 390 //先行判断是否缩略图 如果不是则执行删除image表记录的操作 因为缩略图是没有存到image表记录里面的 391 //isThumbnails := bool(true) //false代表不是缩略图 true代表是缩略图 392 /* 393 if (!strings.HasSuffix(v, "_large.jpg")) && 394 (!strings.HasSuffix(v, "_medium.jpg")) && 395 (!strings.HasSuffix(v, "_small.jpg")) { 396 isThumbnails = false 397 398 } 399 */ 400 //验证是否管理员权限 401 if allow { 402 if err := os.Remove(p); err != nil { 403 log.Println("#", k, ",ROOT DEL FILE ERROR:", err) 404 } 405 406 } else { //检查用户对文件的所有权 407 if helper.VerifyUserfile(p, strconv.FormatInt(uid, 10)) { 408 if err := os.Remove(p); err != nil { 409 log.Println("#", k, ",DEL FILE ERROR:", err) 410 } 411 412 } 413 } 414 415 } 416 } 417 } 418 419 } 420 //不管实际路径中是否存在文件均删除该数据库记录,以免数据库记录陷入死循环无法删掉 421 if node.Id == id { 422 423 if row, err := Engine.Id(id).Delete(new(Node)); err != nil || row == 0 { 424 return errors.New(fmt.Sprint("删除话题错误!", row, err)) //错误还要我自己构造?! 425 } else { 426 return nil 427 } 428 429 } 430 } 431 return errors.New("你无权删除此话题:" + strconv.FormatInt(id, 10)) 432 } 433 return errors.New("无法删除不存在的NODE ID:" + strconv.FormatInt(id, 10)) 434 } 435 436 func GetNodesCount(offset int, limit int) (int64, error) { 437 total, err := Engine.Limit(limit, offset).Count(&Node{}) 438 return total, err 439 } 440 441 func PostNode(node *Node) (int64, error) { 442 return Engine.Insert(node) 443 }