├── public
├── img
│ ├── favicon.ico
│ └── social-icons
│ │ ├── rss.png
│ │ ├── skype.png
│ │ ├── facebook.png
│ │ ├── twitter.png
│ │ ├── youtube.png
│ │ └── vkontakte.png
├── codemirror
│ ├── codemirror.min.js
│ ├── monokai.min.css
│ ├── formatting.min.js
│ ├── codemirror.min.css
│ └── xml.min.js
├── fonts
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── epiceditor
│ └── themes
│ │ └── editor
│ │ └── epic-light.css
├── js
│ ├── admin.js
│ ├── scrolling-nav.js
│ ├── messages_zh.js
│ ├── jquery.metisMenu.js
│ ├── html5shiv.min.js
│ ├── respond.min.js
│ ├── jquery.validate.method.js
│ ├── jquery.easing.min.js
│ └── easykoo.js
└── css
│ ├── front.css
│ ├── zh.txt
│ ├── en.txt
│ ├── dataTables.bootstrap.css
│ └── admin.css
├── common
├── utils_test.go
├── conf.go
├── tsl.go
└── utils.go
├── config.ini
├── model
├── base_test.go
├── comment_test.go
├── user_test.go
├── blog_test.go
├── privilege.go
├── role_test.go
├── category_test.go
├── role.go
├── session.go
├── settings.go
├── base.go
├── category.go
├── link.go
├── comment.go
├── feedback.go
├── visit.go
├── page.go
└── user.go
├── README.md
├── templates
├── layout
│ ├── message.html
│ ├── footer.html
│ ├── blog_side.html
│ ├── front_nav.html
│ └── left.html
├── error
│ └── 403.html
├── profile
│ ├── preferences.html
│ └── password.html
├── user
│ ├── login.html
│ └── register.html
├── index.html
├── blog.html
├── about.html
├── link
│ └── edit.html
├── contact.html
└── admin
│ └── dashboard.html
├── middleware
├── log.go
├── visit.go
├── memory_store.go
├── context.go
├── db_store.go
└── file_store.go
├── .gitattributes
├── dbscripts
├── baseFunction.sql
├── baseData_zh.sql
├── baseData.sql
└── baseSchema.sql
├── handler
├── commonHandler.go
├── adminHandler.go
├── linkHandler.go
├── feedbackHandler.go
└── userHandler.go
├── auth
└── auth.go
├── .gitignore
└── server.go
/public/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/favicon.ico
--------------------------------------------------------------------------------
/public/img/social-icons/rss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/rss.png
--------------------------------------------------------------------------------
/public/img/social-icons/skype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/skype.png
--------------------------------------------------------------------------------
/public/codemirror/codemirror.min.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/codemirror/codemirror.min.js
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/public/img/social-icons/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/facebook.png
--------------------------------------------------------------------------------
/public/img/social-icons/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/twitter.png
--------------------------------------------------------------------------------
/public/img/social-icons/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/youtube.png
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/public/img/social-icons/vkontakte.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/img/social-icons/vkontakte.png
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easykoo/go-blog/HEAD/public/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/common/utils_test.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func Test_Atoa(t *testing.T) {
9 | str := "FirstBlood"
10 | fmt.Println(Atoa(str))
11 | }
12 |
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | log_file=false
2 | log_path=./log.txt
3 | http_port=3000
4 | locale=en
5 |
6 |
7 | [db]
8 | server=127.0.0.1
9 | username=root
10 | password=pass
11 | db_name=easy_go
12 | show_sql=true
--------------------------------------------------------------------------------
/public/epiceditor/themes/editor/epic-light.css:
--------------------------------------------------------------------------------
1 | html { padding:10px; }
2 |
3 | body {
4 | border:0;
5 | background:#fcfcfc;
6 | font-family:monospace;
7 | font-size:14px;
8 | padding:10px;
9 | line-height:1.35em;
10 | margin:0;
11 | padding:0;
12 | }
13 |
--------------------------------------------------------------------------------
/common/conf.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | cfg "github.com/Unknwon/goconfig"
5 | )
6 |
7 | var Cfg *cfg.ConfigFile
8 |
9 | func SetConfig() {
10 | var err error
11 | Cfg, err = cfg.LoadConfigFile("config.ini")
12 | if err != nil {
13 | Cfg, err = cfg.LoadConfigFile("../config.ini")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/model/base_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "testing"
7 | )
8 |
9 | func Init() {
10 | SetConfig()
11 | SetLog()
12 | SetEngine()
13 | }
14 |
15 | func Test_GetHotBlog(t *testing.T) {
16 | Init()
17 | blog := new(DbUtil).GetHotBlog()
18 | Log.Debug(blog)
19 | }
20 |
--------------------------------------------------------------------------------
/model/comment_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "testing"
7 | )
8 |
9 | func init() {
10 | SetConfig()
11 | SetLog()
12 | SetEngine()
13 | }
14 |
15 | func Test_GenerateCommentId(t *testing.T) {
16 | // Init()
17 | comment := new(Comment)
18 | comment.Blog.Id = 1
19 | id, err := comment.GenerateSeq()
20 | PanicIf(err)
21 |
22 | Expect(t, id, 1)
23 | }
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | go-blog
2 | =======
3 | build with [Martini](https://github.com/go-martini/martini), [xorm](https://github.com/go-xorm/xorm) & [goconfig](https://github.com/Unknwon/goconfig)
4 |
5 | ## Getting Started
6 |
7 | After installing Mysql, run script files `baseSchema.sql` & `baseData.sql`.
8 | Change the config `config.ini`, then start the program.
9 |
10 | ## Author
11 |
12 | * [Steven](https://github.com/easykoo)
13 |
--------------------------------------------------------------------------------
/model/user_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "testing"
7 | )
8 |
9 | func Test_user(t *testing.T) {
10 | SetEngine()
11 | user := &User{Username: "test4", Password: "11111", Email: "ddd3@ddd.com"}
12 | user.Delete()
13 | err := user.Insert()
14 | PanicIf(err)
15 |
16 | dbUser, err1 := user.GetUser()
17 | PanicIf(err1)
18 | Expect(t, dbUser.Dept.Id, 1)
19 | Expect(t, dbUser.Role.Id, 3)
20 | }
21 |
--------------------------------------------------------------------------------
/public/js/admin.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | $('#side-menu').metisMenu();
4 |
5 | });
6 |
7 | //Loads the correct sidebar on window load,
8 | //collapses the sidebar on window resize.
9 | $(function () {
10 | $(window).bind("load resize", function () {
11 | if ($(this).width() < 768) {
12 | $('div.sidebar-collapse').addClass('collapse')
13 | } else {
14 | $('div.sidebar-collapse').removeClass('collapse')
15 | }
16 | })
17 | })
--------------------------------------------------------------------------------
/templates/layout/message.html:
--------------------------------------------------------------------------------
1 | {{with .Messages}}
2 |
3 | ×
5 | {{range .}}
6 | {{.}}
7 | {{end}}
8 |
9 | {{end}}
10 | {{with .Errors}}
11 | {{range . }}
12 |
13 | ×
15 | {{.}}
16 |
17 | {{end}}
18 | {{end}}
--------------------------------------------------------------------------------
/model/blog_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "testing"
7 | )
8 |
9 | func Test_SearchTag(t *testing.T) {
10 | SetConfig()
11 | SetLog()
12 | SetEngine()
13 | result, err := orm.Query("select name, count(name) as count from tag group by name order by count desc")
14 | PanicIf(err)
15 | var tagInfoArray []TagInfo
16 | for _, val := range result {
17 | tagInfoArray = append(tagInfoArray, TagInfo{Name: string(val["name"]), Count: ParseInt(string(val["count"]))})
18 | }
19 |
20 | Log.Debug(tagInfoArray)
21 | }
22 |
--------------------------------------------------------------------------------
/middleware/log.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/go-martini/martini"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 |
8 | "net/http"
9 | "time"
10 | )
11 |
12 | func GetLogger() martini.Handler {
13 | return func(res http.ResponseWriter, req *http.Request, c martini.Context) {
14 | start := time.Now()
15 | Log.Debugf("Started %s %s", req.Method, req.URL.Path)
16 |
17 | rw := res.(martini.ResponseWriter)
18 | c.Next()
19 |
20 | Log.Debugf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start))
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/public/css/front.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-top: 100px;
3 | word-wrap: break-word;
4 | }
5 |
6 | @media (max-width: 460px) {
7 | #side {
8 | width: 100%;
9 | }
10 | }
11 |
12 | footer {
13 | padding: 30px 0;
14 | }
15 |
16 | .tag {
17 | margin-top: 5px;
18 | cursor: pointer;
19 | }
20 |
21 | .gray {
22 | color: #ABABAB;
23 | }
24 |
25 | .container {
26 | font-family: Ubuntu, Consolas, "Microsoft YaHei", Verdana, Tahoma, Arial, sans-serif;
27 | font-size: 14px;
28 | }
29 |
30 | .page {
31 | text-align: center;
32 | }
33 |
34 | #editor {
35 | border: 1px solid rgb(204, 204, 204);
36 | border-radius: 4px;
37 | }
--------------------------------------------------------------------------------
/common/tsl.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "fmt"
5 | cfg "github.com/Unknwon/goconfig"
6 | "strings"
7 | )
8 |
9 | var Tsl *cfg.ConfigFile
10 |
11 | func init() {
12 | Tsl, _ = cfg.LoadConfigFile("messages.ini")
13 | }
14 |
15 | func Translate(lang string, format string) string {
16 | if lang == "" || !strings.Contains(lang, "zh") {
17 | lang = "en"
18 | }
19 | return Tsl.MustValue(lang, format, format)
20 | }
21 |
22 | func Translatef(lang string, format string, args ...interface{}) string {
23 | if lang == "" || !strings.Contains(lang, "zh") {
24 | lang = "en"
25 | }
26 | return fmt.Sprintf(Tsl.MustValue(lang, format, format), args)
27 | }
28 |
--------------------------------------------------------------------------------
/dbscripts/baseFunction.sql:
--------------------------------------------------------------------------------
1 | DROP FUNCTION if exists generateCategoryId;
2 | DELIMITER $$
3 | CREATE FUNCTION generateCategoryId (parentId VARCHAR(20)) RETURNS VARCHAR(50)
4 | begin
5 | declare tempId varchar(20);
6 | if parentId is null or parentId = '' or parentId = 0 then
7 | select max(id) + 1 into tempId from category;
8 | set tempId = ifnull(tempId, '101');
9 | else
10 | select cast(max(cast(id as unsigned)) + 1 as char(20)) into tempId from category where parent_id = parentId;
11 | if tempId is null then
12 | select concat(parentId, '001') into tempId;
13 | end if;
14 | end if;
15 | RETURN tempId;
16 | END$$
17 | DELIMITER ;
--------------------------------------------------------------------------------
/public/js/scrolling-nav.js:
--------------------------------------------------------------------------------
1 | //jQuery to collapse the navbar on scroll
2 | $(window).scroll(function() {
3 | if ($(".navbar").offset().top > 50) {
4 | $(".navbar-fixed-top").addClass("top-nav-collapse");
5 | } else {
6 | $(".navbar-fixed-top").removeClass("top-nav-collapse");
7 | }
8 | });
9 |
10 | //jQuery for page scrolling feature - requires jQuery Easing plugin
11 | $(function() {
12 | $('.page-scroll a').bind('click', function(event) {
13 | var $anchor = $(this);
14 | $('html, body').stop().animate({
15 | scrollTop: $($anchor.attr('href')).offset().top
16 | }, 1500, 'easeInOutExpo');
17 | event.preventDefault();
18 | });
19 | });
--------------------------------------------------------------------------------
/public/css/zh.txt:
--------------------------------------------------------------------------------
1 | {
2 | "sProcessing": "处理中...",
3 | "sLengthMenu": "显示 _MENU_ 项结果",
4 | "sZeroRecords": "没有匹配结果",
5 | "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
6 | "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
7 | "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
8 | "sInfoPostFix": "",
9 | "sSearch": "搜索:",
10 | "sUrl": "",
11 | "sEmptyTable": "表中数据为空",
12 | "sLoadingRecords": "载入中...",
13 | "sInfoThousands": ",",
14 | "oPaginate": {
15 | "sFirst": "首页",
16 | "sPrevious": "上页",
17 | "sNext": "下页",
18 | "sLast": "末页"
19 | },
20 | "oAria": {
21 | "sSortAscending": ": 以升序排列此列",
22 | "sSortDescending": ": 以降序排列此列"
23 | }
24 | }
--------------------------------------------------------------------------------
/middleware/visit.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/easykoo/sessions"
5 | "github.com/go-martini/martini"
6 |
7 | . "github.com/easykoo/go-blog/common"
8 | "github.com/easykoo/go-blog/model"
9 |
10 | "net/http"
11 | "reflect"
12 | )
13 |
14 | func RecordVisit() martini.Handler {
15 | return func(s sessions.Session, r *http.Request) {
16 | visit := new(model.Visit)
17 | visit.SessionId = s.GetId()
18 | user := s.Get("SignedUser")
19 | var id int
20 | if user != nil {
21 | if reflect.TypeOf(user).Kind() == reflect.Struct {
22 | id = user.(model.User).Id
23 | } else {
24 | id = user.(*model.User).Id
25 | }
26 | }
27 | visit.User = model.User{Id: id}
28 | visit.Ip = GetRemoteIp(r)
29 | if visit.ExistVisit() {
30 | visit.Update()
31 | } else {
32 | visit.Insert()
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/public/css/en.txt:
--------------------------------------------------------------------------------
1 | {
2 | "sEmptyTable": "No data available in table",
3 | "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
4 | "sInfoEmpty": "Showing 0 to 0 of 0 entries",
5 | "sInfoFiltered": "(filtered from _MAX_ total entries)",
6 | "sInfoPostFix": "",
7 | "sInfoThousands": ",",
8 | "sLengthMenu": "Show _MENU_ entries",
9 | "sLoadingRecords": "Loading...",
10 | "sProcessing": "Processing...",
11 | "sSearch": "Search:",
12 | "sZeroRecords": "No matching records found",
13 | "oPaginate": {
14 | "sFirst": "First",
15 | "sLast": "Last",
16 | "sNext": "Next",
17 | "sPrevious": "Previous"
18 | },
19 | "oAria": {
20 | "sSortAscending": ": activate to sort column ascending",
21 | "sSortDescending": ": activate to sort column descending"
22 | }
23 | }
--------------------------------------------------------------------------------
/public/js/messages_zh.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Translated default messages for the jQuery validation plugin.
3 | * Locale: ZH (Chinese, 中文 (Zhōngwén), 汉语, 漢語)
4 | */
5 | (function($) {
6 | $.extend($.validator.messages, {
7 | required: "必须填写",
8 | remote: "请修正此栏位",
9 | email: "请输入有效的电子邮件",
10 | url: "请输入有效的网址",
11 | date: "请输入有效的日期",
12 | dateISO: "请输入有效的日期 (YYYY-MM-DD)",
13 | number: "请输入正确的数字",
14 | digits: "只可输入数字",
15 | creditcard: "请输入有效的信用卡号码",
16 | equalTo: "你的输入不相同",
17 | extension: "请输入有效的后缀",
18 | maxlength: $.validator.format("最多 {0} 个字"),
19 | minlength: $.validator.format("最少 {0} 个字"),
20 | rangelength: $.validator.format("请输入长度为 {0} 至 {1} 之間的字串"),
21 | range: $.validator.format("请输入 {0} 至 {1} 之间的数值"),
22 | max: $.validator.format("请输入不大于 {0} 的数值"),
23 | min: $.validator.format("请输入不小于 {0} 的数值")
24 | });
25 | }(jQuery));
--------------------------------------------------------------------------------
/handler/commonHandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/go-martini/martini"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 | "github.com/easykoo/go-blog/middleware"
8 | "github.com/easykoo/go-blog/model"
9 | )
10 |
11 | func Index(ctx *middleware.Context) {
12 | ctx.HTML(200, "index", ctx)
13 | }
14 |
15 | func About(ctx *middleware.Context) {
16 | ctx.HTML(200, "about", ctx)
17 | }
18 |
19 | func ContactHandler(ctx *middleware.Context, feedback model.Feedback) {
20 | switch ctx.R.Method {
21 | case "POST":
22 | err := feedback.Insert()
23 | PanicIf(err)
24 | ctx.Set("success", true)
25 | ctx.Set("message", Translate(ctx.S.Get("Lang").(string), "message.send.success"))
26 | ctx.JSON(200, ctx.Response)
27 | default:
28 | ctx.HTML(200, "contact", ctx)
29 | }
30 | }
31 |
32 | func LangHandler(ctx *middleware.Context, params martini.Params) {
33 | lang := params["lang"]
34 | ctx.S.Set("Lang", lang)
35 | ctx.Set("success", true)
36 | ctx.JSON(200, ctx.Response)
37 | }
38 |
--------------------------------------------------------------------------------
/model/privilege.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import "time"
4 |
5 | type Privilege struct {
6 | ModuleId int `xorm:"int(11) default 3"`
7 | RoleId int `xorm:"int(11) default 3"`
8 | DeptId int `xorm:"int(11) default 3"`
9 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
10 | CreateDate time.Time `xorm:"datetime created"`
11 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
12 | UpdateDate time.Time `xorm:"datetime updated"`
13 | }
14 |
15 | type Module struct {
16 | Id int `xorm:"int(3) pk not null"`
17 | description string `xorm:"varchar(40) not null"`
18 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
19 | CreateDate time.Time `xorm:"datetime created"`
20 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
21 | UpdateDate time.Time `xorm:"datetime updated"`
22 | }
23 |
24 | func (self *Privilege) CheckModulePrivilege() (bool, error) {
25 | privilege := &Privilege{ModuleId: self.ModuleId, RoleId: self.RoleId, DeptId: self.DeptId}
26 | return orm.Get(privilege)
27 | }
28 |
--------------------------------------------------------------------------------
/public/codemirror/monokai.min.css:
--------------------------------------------------------------------------------
1 | .cm-s-monokai.CodeMirror{background:#272822;color:#f8f8f2}.cm-s-monokai div.CodeMirror-selected{background:#49483e!important}.cm-s-monokai .CodeMirror-gutters{background:#272822;border-right:0}.cm-s-monokai .CodeMirror-linenumber{color:#d0d0d0}.cm-s-monokai .CodeMirror-cursor{border-left:1px solid #f8f8f0!important}.cm-s-monokai span.cm-comment{color:#75715e}.cm-s-monokai span.cm-atom{color:#ae81ff}.cm-s-monokai span.cm-number{color:#ae81ff}.cm-s-monokai span.cm-property,.cm-s-monokai span.cm-attribute{color:#a6e22e}.cm-s-monokai span.cm-keyword{color:#f92672}.cm-s-monokai span.cm-string{color:#e6db74}.cm-s-monokai span.cm-variable{color:#a6e22e}.cm-s-monokai span.cm-variable-2{color:#9effff}.cm-s-monokai span.cm-def{color:#fd971f}.cm-s-monokai span.cm-bracket{color:#f8f8f2}.cm-s-monokai span.cm-tag{color:#f92672}.cm-s-monokai span.cm-link{color:#ae81ff}.cm-s-monokai span.cm-error{background:#f92672;color:#f8f8f0}.cm-s-monokai .CodeMirror-activeline-background{background:#373831!important}.cm-s-monokai .CodeMirror-matchingbracket{text-decoration:underline;color:white!important}
--------------------------------------------------------------------------------
/model/role_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "fmt"
7 | "testing"
8 | )
9 |
10 | type RoleTest struct {
11 | Id int `form:"id" xorm:"int(3) pk not null autoincr"`
12 | Desc string `form:"description" xorm:"varchar(20) not null"`
13 | }
14 |
15 | type UserTest struct {
16 | Id int `form:"id" xorm:"int(11) pk not null autoincr"`
17 | Username string `form:"username" xorm:"varchar(20) not null"`
18 | Role Role `xorm:"role_id int(3) default 3"`
19 | }
20 |
21 | func Test_RoleTest(t *testing.T) {
22 | SetEngine()
23 | err := orm.DropTables(&RoleTest{}, &UserTest{})
24 | if err != nil {
25 | fmt.Println(err)
26 | return
27 | }
28 |
29 | err = orm.CreateTables(&RoleTest{}, &UserTest{})
30 | if err != nil {
31 | fmt.Println(err)
32 | return
33 | }
34 |
35 | _, err = orm.Insert(&RoleTest{Id: 1, Desc: "test1"}, &UserTest{Id: 1, Username: "username"})
36 | if err != nil {
37 | fmt.Println(err)
38 | return
39 | }
40 |
41 | userTest := UserTest{}
42 | _, err = orm.Id(1).Get(&UserTest{})
43 | if err != nil {
44 | fmt.Println(err)
45 | return
46 | }
47 | fmt.Println(userTest)
48 |
49 | Expect(t, userTest.Role.Id, 1)
50 | }
51 |
--------------------------------------------------------------------------------
/templates/layout/footer.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/model/category_test.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "fmt"
7 | "testing"
8 | )
9 |
10 | func Test_Category(t *testing.T) {
11 | SetConfig()
12 | SetLog()
13 | SetEngine()
14 | err := orm.DropTables(&Category{})
15 | if err != nil {
16 | fmt.Println(err)
17 | return
18 | }
19 |
20 | err = orm.CreateTables(&Category{})
21 | if err != nil {
22 | fmt.Println(err)
23 | return
24 | }
25 |
26 | _, err = orm.Insert(&Category{Id: 1, Description: "test1"}, &Category{Id: 2, Description: "test2"}, &Category{Id: 3, Description: "test3"})
27 | if err != nil {
28 | fmt.Println(err)
29 | return
30 | }
31 |
32 | category := Category{}
33 | _, err = orm.Id(1).Get(&category)
34 | if err != nil {
35 | fmt.Println(err)
36 | return
37 | }
38 | fmt.Println(category)
39 |
40 | Expect(t, category.Id, 1)
41 | }
42 |
43 | func Test_SearchCategory(t *testing.T) {
44 | SetConfig()
45 | SetLog()
46 | SetEngine()
47 | category := new(Category)
48 | blogList, total, err := category.SearchByPage()
49 | Log.Debug(blogList, total, err)
50 | }
51 |
52 | func Test_GenerateCategoryId(t *testing.T) {
53 | SetConfig()
54 | SetLog()
55 | SetEngine()
56 | category := new(Category)
57 | id, err := category.GenerateCategoryId(0)
58 | PanicIf(err)
59 |
60 | Expect(t, id, 101)
61 | }
62 |
--------------------------------------------------------------------------------
/model/role.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Role struct {
8 | Id int `form:"roleId" xorm:"int(3) pk not null autoincr"`
9 | Description string `form:"description" xorm:"varchar(20) not null"`
10 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
11 | CreateDate time.Time `xorm:"datetime created"`
12 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
13 | UpdateDate time.Time `xorm:"datetime updated"`
14 | Version int `form:"version" xorm:"int(11) version"`
15 | }
16 |
17 | func (self *Role) GetRoleById(id int) (*Role, error) {
18 | role := &Role{Id: id}
19 | _, err := orm.Get(role)
20 | return role, err
21 | }
22 |
23 | type Dept struct {
24 | Id int `form:"deptId" xorm:"int(3) pk not null autoincr"`
25 | Description string `form:"description" xorm:"varchar(20) not null"`
26 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
27 | CreateDate time.Time `xorm:"datetime created"`
28 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
29 | UpdateDate time.Time `xorm:"datetime updated"`
30 | Version int `form:"version" xorm:"int(11) version"`
31 | }
32 |
33 | func (self *Dept) GetRoleById(id int) (*Dept, error) {
34 | dept := &Dept{Id: id}
35 | _, err := orm.Get(dept)
36 | return dept, err
37 | }
38 |
--------------------------------------------------------------------------------
/templates/error/403.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | No Permission
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
403 - No Permission
20 |
21 |
22 |
23 | Please contact the administrator.
24 | Go Back
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/model/session.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "time"
7 | )
8 |
9 | type SessionInfo struct {
10 | Id string `xorm:"varchar(60) pk not null "`
11 | Content string `xorm:"varchar(15) null"`
12 | Age int `xorm:"int(9)"`
13 | CreateDate time.Time `xorm:"datetime created"`
14 | UpdateDate time.Time `xorm:"datetime updated"`
15 | }
16 |
17 | func (self *SessionInfo) Exist() (exist bool) {
18 | exist, err := orm.Get(&SessionInfo{Id: self.Id})
19 | PanicIf(err)
20 | return
21 | }
22 |
23 | func (self *SessionInfo) GetSessionInfo() (sessionInfo SessionInfo) {
24 | _, err := orm.Id(self.Id).Get(&sessionInfo)
25 | PanicIf(err)
26 | return
27 | }
28 |
29 | func (self *SessionInfo) Insert() error {
30 | _, err := orm.InsertOne(self)
31 | Log.Info("SessionInfo ", self.Id, " inserted")
32 | return err
33 | }
34 |
35 | func (self *SessionInfo) Update() error {
36 | _, err := orm.Id(self.Id).Update(self)
37 | Log.Info("SessionInfo ", self.Id, " updated")
38 | return err
39 | }
40 |
41 | func (self *SessionInfo) Delete() error {
42 | _, err := orm.Delete(self)
43 | Log.Info("SessionInfo ", self.Id, " deleted")
44 | return err
45 | }
46 |
47 | func (self *SessionInfo) RemoveExpiredSession() (err error) {
48 | _, err = orm.Exec("delete from session_info where UNIX_TIMESTAMP(now()) >= age + UNIX_TIMESTAMP(update_date)")
49 | return
50 | }
51 |
--------------------------------------------------------------------------------
/handler/adminHandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 | "github.com/easykoo/go-blog/middleware"
6 | "github.com/easykoo/go-blog/model"
7 | )
8 |
9 | func DashboardHandler(ctx *middleware.Context) {
10 | visit := new(model.Visit)
11 | visit.SetPageActive(true)
12 | visit.SetPageSize(10)
13 | pageNo := ParseInt(ctx.R.FormValue("page"))
14 | visit.SetPageNo(pageNo)
15 | visit.AddSortProperty("create_date", "desc")
16 | visitList, total, err := visit.SearchByPage()
17 | PanicIf(err)
18 |
19 | visit.SetTotalRecord(total)
20 | visit.Result = visitList
21 | ctx.Set("Visit", visit)
22 | ctx.HTML(200, "admin/dashboard", ctx)
23 | }
24 |
25 | func SettingsHandler(ctx *middleware.Context, settings model.Settings) {
26 | if ctx.R.Method == "POST" {
27 | err := settings.Update()
28 | PanicIf(err)
29 | dbSettings := model.GetSettings()
30 | ctx.AddMessage(Translate(ctx.S.Get("Lang").(string), "message.change.success"))
31 | ctx.S.Set("Settings", dbSettings)
32 | }
33 | user := &model.User{}
34 | users, err := user.SelectAll()
35 | PanicIf(err)
36 | ctx.Set("Users", users)
37 |
38 | ctx.HTML(200, "admin/settings", ctx)
39 | }
40 |
41 | func AboutHandler(ctx *middleware.Context) {
42 | settings := model.GetSettings()
43 | about := ctx.R.FormValue("about")
44 | settings.About = about
45 | err := settings.Update()
46 | PanicIf(err)
47 | dbSettings := model.GetSettings()
48 | ctx.S.Set("Settings", dbSettings)
49 |
50 | ctx.Redirect("/about")
51 | }
52 |
--------------------------------------------------------------------------------
/model/settings.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "time"
7 | )
8 |
9 | type Settings struct {
10 | Id int `form:"settingsId" xorm:"int(11) pk not null autoincr"`
11 | AppName string `form:"appName" xorm:"varchar(45) not null"`
12 | About string `form:"about" xorm:"blob not null"`
13 | Owner User `form:"owner_id" json:"owner_id" xorm:"owner_id"`
14 | Keywords string `form:"keywords" xorm:"varchar(100) default null"`
15 | Description string `form:"description" xorm:"varchar(100) default null"`
16 | CreateUser string `xorm:"varchar(20) default null"`
17 | CreateDate time.Time `xorm:"datetime created"`
18 | UpdateUser string `xorm:"varchar(20) default null"`
19 | UpdateDate time.Time `xorm:"datetime updated"`
20 | Version int `form:"version" xorm:"int(11) version"`
21 | Page `xorm:"-"`
22 | }
23 |
24 | func GetSettings() *Settings {
25 | settings := &Settings{Id: 1}
26 | _, err := orm.Get(settings)
27 | PanicIf(err)
28 | return settings
29 | }
30 |
31 | func (self *Settings) Insert() error {
32 | _, err := orm.InsertOne(self)
33 | Log.Info("Settings ", self.Id, " inserted")
34 | return err
35 | }
36 |
37 | func (self *Settings) Update() error {
38 | _, err := orm.Id(self.Id).Update(self)
39 | Log.Info("Settings ", self.Id, " updated!")
40 | return err
41 | }
42 |
43 | func (self *Settings) Delete() error {
44 | _, err := orm.Delete(self)
45 | Log.Info("Settings ", self.Id, " deleted")
46 | return err
47 | }
48 |
--------------------------------------------------------------------------------
/public/js/jquery.metisMenu.js:
--------------------------------------------------------------------------------
1 | ;(function ($, window, document, undefined) {
2 |
3 | var pluginName = "metisMenu",
4 | defaults = {
5 | toggle: true
6 | };
7 |
8 | function Plugin(element, options) {
9 | this.element = element;
10 | this.settings = $.extend({}, defaults, options);
11 | this._defaults = defaults;
12 | this._name = pluginName;
13 | this.init();
14 | }
15 |
16 | Plugin.prototype = {
17 | init: function () {
18 |
19 | var $this = $(this.element),
20 | $toggle = this.settings.toggle;
21 |
22 | $this.find('li.active').has('ul').children('ul').addClass('collapse in');
23 | $this.find('li').not('.active').has('ul').children('ul').addClass('collapse');
24 |
25 | $this.find('li').has('ul').children('a').on('click', function (e) {
26 | e.preventDefault();
27 |
28 | $(this).parent('li').toggleClass('active').children('ul').collapse('toggle');
29 |
30 | if ($toggle) {
31 | $(this).parent('li').siblings().removeClass('active').children('ul.in').collapse('hide');
32 | }
33 | });
34 | }
35 | };
36 |
37 | $.fn[ pluginName ] = function (options) {
38 | return this.each(function () {
39 | if (!$.data(this, "plugin_" + pluginName)) {
40 | $.data(this, "plugin_" + pluginName, new Plugin(this, options));
41 | }
42 | });
43 | };
44 |
45 | })(jQuery, window, document);
46 |
--------------------------------------------------------------------------------
/model/base.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | _ "github.com/go-sql-driver/mysql"
5 | "github.com/go-xorm/xorm"
6 |
7 | . "github.com/easykoo/go-blog/common"
8 | "time"
9 | )
10 |
11 | var orm *xorm.Engine
12 |
13 | func SetEngine() *xorm.Engine {
14 | Log.Info("db initializing...")
15 | var err error
16 | server := Cfg.MustValue("db", "server", "127.0.0.1")
17 | username := Cfg.MustValue("db", "username", "root")
18 | password := Cfg.MustValue("db", "password", "pass")
19 | dbName := Cfg.MustValue("db", "db_name", "go_display")
20 | orm, err = xorm.NewEngine("mysql", username+":"+password+"@tcp("+server+":3306)/"+dbName+"?charset=utf8")
21 | PanicIf(err)
22 | orm.TZLocation = time.Local
23 | orm.ShowSQL = Cfg.MustBool("db", "show_sql", false)
24 | orm.Logger = xorm.NewSimpleLogger(Log.GetWriter())
25 | return orm
26 | }
27 |
28 | type DbUtil struct{}
29 |
30 | func (self *DbUtil) GetRecentComments() (comments []Comment) {
31 | err := orm.OrderBy("create_date desc").Limit(5, 0).Find(&comments, &Comment{})
32 | PanicIf(err)
33 | return
34 | }
35 |
36 | func (self *DbUtil) GetHotBlog() (blog []Blog) {
37 | result, err := orm.Query("select * from blog b, (select blog_id, count(*) count from comment group by blog_id order by count desc limit 0,5) t where b.id = t.blog_id order by t.count desc, b.create_date desc")
38 | PanicIf(err)
39 | for _, val := range result {
40 | b := Blog{Id: int(ParseInt(string(val["id"]))), Title: string(val["title"])}
41 | blog = append(blog, b)
42 | }
43 | return
44 | }
45 |
46 | func (self *DbUtil) GetAllLinks() (links []Link) {
47 | err := orm.OrderBy("create_date desc").Find(&links, &Link{})
48 | PanicIf(err)
49 | return links
50 | }
51 |
--------------------------------------------------------------------------------
/model/category.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "time"
7 | )
8 |
9 | type Category struct {
10 | Id int `form:"id" xorm:"int(3) pk not null autoincr"`
11 | Description string `form:"description" xorm:"varchar(20) not null"`
12 | ParentId int `form:"parentId" xorm:"int(3)"`
13 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
14 | CreateDate time.Time `xorm:"datetime created"`
15 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
16 | UpdateDate time.Time `xorm:"datetime updated"`
17 | Version int `form:"version" xorm:"int(11) version"`
18 | Page `xorm:"-"`
19 | }
20 |
21 | func (self *Category) insert() (int64, error) {
22 | id, err := self.GenerateCategoryId(self.ParentId)
23 | PanicIf(err)
24 | self.Id = id
25 | return orm.Insert(self)
26 | }
27 |
28 | func (self *Category) GetCategoryById(id int) (*Category, error) {
29 | category := &Category{Id: id}
30 | _, err := orm.Get(category)
31 | return category, err
32 | }
33 |
34 | func (self *Category) SearchByPage() ([]Category, int, error) {
35 | total, err := orm.Count(self)
36 | var category []Category
37 |
38 | session := orm.NewSession()
39 | defer session.Close()
40 | if len(self.GetSortProperties()) > 0 {
41 | session = session.OrderBy(self.GetSortProperties()[0].Column + " " + self.GetSortProperties()[0].Direction)
42 | }
43 | err = session.Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&category, self)
44 | return category, int(total), err
45 | }
46 |
47 | func (self *Category) GenerateCategoryId(parentId int) (int, error) {
48 | result, err := orm.Query("select generateCategoryId(?) as id", IntString(parentId))
49 | return ParseInt(string(result[0]["id"])), err
50 | }
51 |
--------------------------------------------------------------------------------
/auth/auth.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "github.com/go-martini/martini"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 | "github.com/easykoo/go-blog/middleware"
8 | "github.com/easykoo/go-blog/model"
9 |
10 | "reflect"
11 | )
12 |
13 | const (
14 | SignInRequired = 9
15 | Module_Admin = iota
16 | Module_Account
17 | Module_Feedback
18 | Module_News
19 | Module_Product
20 | Module_Blog
21 | Module_Link
22 | )
23 |
24 | func AuthRequest(req interface{}) martini.Handler {
25 | return func(ctx *middleware.Context) {
26 | Log.Info("Checking privilege: ", ctx.R.RequestURI)
27 | switch req {
28 | case SignInRequired:
29 | Log.Info("Checking style: ", "SignInRequired")
30 | if user := ctx.S.Get("SignedUser"); user != nil {
31 | Log.Info("Pass!")
32 | return
33 | }
34 | ctx.Redirect("/user/login")
35 | return
36 | default:
37 | Log.Info("Checking style: ", "Module ", req.(int))
38 | if user := ctx.S.Get("SignedUser"); user != nil {
39 | if reflect.TypeOf(req).Kind() == reflect.Int {
40 | if CheckPermission(user, req.(int)) {
41 | Log.Info("Pass!")
42 | return
43 | }
44 | ctx.HTML(403, "error/403", ctx)
45 | return
46 | }
47 | } else {
48 | ctx.Redirect("/user/login")
49 | return
50 | }
51 | ctx.HTML(403, "error/403", ctx)
52 | return
53 | }
54 | }
55 | }
56 |
57 | func CheckPermission(user interface{}, module int) bool {
58 | if reflect.TypeOf(user).Kind() == reflect.Struct {
59 | val := user.(model.User)
60 | privilege := &model.Privilege{ModuleId: module, RoleId: val.Role.Id, DeptId: val.Dept.Id}
61 | exist, err := privilege.CheckModulePrivilege()
62 | PanicIf(err)
63 | return exist
64 | } else {
65 | val := user.(*model.User)
66 | privilege := &model.Privilege{ModuleId: module, RoleId: val.Role.Id, DeptId: val.Dept.Id}
67 | exist, err := privilege.CheckModulePrivilege()
68 | PanicIf(err)
69 | return exist
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/model/link.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 | "time"
6 | )
7 |
8 | type Link struct {
9 | Id int `form:"id" xorm:"int(3) pk not null autoincr"`
10 | Description string `form:"description" xorm:"varchar(40) not null"`
11 | Url string `form:"url" xorm:"varchar(80) not null"`
12 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
13 | CreateDate time.Time `xorm:"datetime created"`
14 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
15 | UpdateDate time.Time `xorm:"datetime updated"`
16 | Version int `form:"version" xorm:"int(11) version"`
17 | Page `xorm:"-"`
18 | }
19 |
20 | func (self *Link) Insert() error {
21 | session := orm.NewSession()
22 | defer session.Close()
23 | _, err := session.InsertOne(self)
24 | Log.Info("Link ", self.Id, " inserted")
25 | return err
26 | }
27 |
28 | func (self *Link) Update() error {
29 | session := orm.NewSession()
30 | defer session.Close()
31 | _, err := session.Id(self.Id).Update(self)
32 | Log.Info("Link ", self.Id, " updated!")
33 | return err
34 | }
35 |
36 | func (self *Link) Delete() error {
37 | session := orm.NewSession()
38 | defer session.Close()
39 | _, err := session.Delete(self)
40 | Log.Info("Link ", self.Id, " deleted")
41 | return err
42 | }
43 |
44 | func (self *Link) GetLinkById() (*Link, error) {
45 | link := &Link{Id: self.Id}
46 | _, err := orm.Get(link)
47 | return link, err
48 | }
49 |
50 | func (self *Link) GetLink() error {
51 | _, err := orm.Id(self.Id).Get(self)
52 | return err
53 | }
54 |
55 | func (self *Link) DeleteLinkArray(array []int) error {
56 | _, err := orm.In("id", array).Delete(&Link{})
57 | Log.Info("Link Array: ", array, " deleted")
58 | return err
59 | }
60 |
61 | func (self *Link) SearchByPage() ([]Link, int, error) {
62 | total, err := orm.Count(self)
63 | var link []Link
64 | err = orm.OrderBy(self.GetSortProperties()[0].Column+" "+self.GetSortProperties()[0].Direction).Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&link, self)
65 | return link, int(total), err
66 | }
67 |
--------------------------------------------------------------------------------
/common/utils.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | "io"
7 | "math/rand"
8 | "net/http"
9 | "os"
10 | "reflect"
11 | "strconv"
12 | "strings"
13 | "testing"
14 | "time"
15 | )
16 |
17 | var Log *Logger
18 |
19 | func SetLog() {
20 | var out io.Writer
21 | if Cfg.MustBool("", "log_file", false) {
22 | f, _ := os.OpenFile(Cfg.MustValue("", "log_path", "./log.txt"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
23 | out = io.MultiWriter(f)
24 | } else {
25 | out = os.Stdout
26 | }
27 | Log = New(out, "[go-blog]", Lshortfile|Ldate|Lmicroseconds)
28 | }
29 |
30 | func PanicIf(err error) {
31 | if err != nil {
32 | panic(err)
33 | }
34 | }
35 |
36 | func ParseInt(value string) int {
37 | if value == "" {
38 | return 0
39 | }
40 | val, _ := strconv.Atoi(value)
41 | return val
42 | }
43 |
44 | func IntString(value int) string {
45 | return strconv.Itoa(value)
46 | }
47 |
48 | func Md5(str string) string {
49 | h := md5.New()
50 | h.Write([]byte(str))
51 | return hex.EncodeToString(h.Sum(nil))
52 | }
53 |
54 | func Atoa(str string) string {
55 | var result string
56 | for i := 0; i < len(str); i++ {
57 | c := rune(str[i])
58 | if 'A' <= c && c <= 'Z' && i > 0 {
59 | result = result + "_" + strings.ToLower(string(str[i]))
60 | } else {
61 | result = result + string(str[i])
62 | }
63 | }
64 | return result
65 | }
66 |
67 | func GetRemoteIp(r *http.Request) (ip string) {
68 | ip = r.Header.Get("X-Real-Ip")
69 | if ip == "" {
70 | ip = r.RemoteAddr
71 | }
72 | ip = strings.Split(ip, ":")[0]
73 | if len(ip) < 7 || ip == "127.0.0.1" {
74 | ip = "localhost"
75 | }
76 | return
77 | }
78 |
79 | /* Test Helpers */
80 | func Expect(t *testing.T, a interface{}, b interface{}) {
81 | if a != b {
82 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
83 | }
84 | }
85 |
86 | func GenToken() string {
87 | nano := time.Now().UnixNano()
88 | rand.Seed(nano)
89 | rndNum := rand.Int63()
90 | uuid := Md5(Md5(strconv.FormatInt(nano, 10)) + Md5(strconv.FormatInt(rndNum, 10)))
91 | return uuid
92 | }
93 |
--------------------------------------------------------------------------------
/model/comment.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "time"
7 | )
8 |
9 | type Comment struct {
10 | Blog Blog `xorm:"blog_id int(11) pk not null"`
11 | Seq int `xorm:"int(5) pk not null"`
12 | Name string `form:"name" xorm:"varchar(20) null"`
13 | Www string `form:"www" xorm:"varchar(45) null"`
14 | Email string `form:"email" xorm:"varchar(45) null"`
15 | Content string `form:"content" xorm:"varchar(150) not null"`
16 | ParentSeq int `form:"prentSeq" xorm:"int(5) null"`
17 | Ip string `xorm:"varchar(15) null"`
18 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
19 | CreateDate time.Time `xorm:"datetime created"`
20 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
21 | UpdateDate time.Time `xorm:"datetime updated"`
22 | Version int `form:"version" xorm:"int(11) version"`
23 | Page `xorm:"-"`
24 | }
25 |
26 | func (self *Comment) GenerateSeq() (int, error) {
27 | result, err := orm.Query("select max(seq)+1 as seq from comment where blog_id = ?", self.Blog.Id)
28 | seq := ParseInt(string(result[0]["seq"]))
29 | if seq < 1 {
30 | seq = 1
31 | }
32 | return seq, err
33 | }
34 |
35 | func (self *Comment) Insert() error {
36 | seq, err := self.GenerateSeq()
37 | self.Seq = seq
38 | _, err = orm.InsertOne(self)
39 | Log.Info("Comment ", self.Blog.Id, " ", self.Seq, " inserted")
40 | return err
41 | }
42 |
43 | func (self *Comment) Update() error {
44 | _, err := orm.Update(self)
45 | Log.Info("Comment ", self.Blog.Id, " ", self.Seq, " updated")
46 | return err
47 | }
48 |
49 | func (self *Comment) Delete() error {
50 | _, err := orm.Delete(self)
51 | Log.Info("Comment ", self.Blog.Id, " ", self.Seq, " deleted")
52 | return err
53 | }
54 |
55 | func (self *Comment) SearchByPage() ([]Comment, int64, error) {
56 | total, err := orm.Count(self)
57 | var comment []Comment
58 | err = orm.OrderBy(self.GetSortProperties()[0].Column+" "+self.GetSortProperties()[0].Direction).Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&comment, self)
59 | return comment, total, err
60 | }
61 |
--------------------------------------------------------------------------------
/model/feedback.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "strconv"
7 | "time"
8 | )
9 |
10 | type Feedback struct {
11 | Id int `xorm:"int(11) pk not null autoincr"`
12 | Name string `form:"name" xorm:"varchar(20) not null"`
13 | Email string `form:"email" xorm:"varchar(45) unique"`
14 | Content string `form:"content" xorm:"varchar(45) unique"`
15 | Viewed bool `xorm:"tinyint(1) default 0"`
16 | CreateDate time.Time `xorm:"datetime created"`
17 | ViewDate time.Time `xorm:"datetime updated"`
18 | Page `xorm:"-"`
19 | }
20 |
21 | func (self *Feedback) Insert() error {
22 | _, err := orm.InsertOne(self)
23 | Log.Info("Feedback ", self.Id, " inserted")
24 | return err
25 | }
26 |
27 | func (self *Feedback) Delete() error {
28 | _, err := orm.Delete(self)
29 | Log.Info("Feedback ", self.Id, " deleted")
30 | return err
31 | }
32 |
33 | func (self *Feedback) SetViewed(view bool) error {
34 | var err error
35 | _, err = orm.Id(self.Id).UseBool("viewed").Update(&Feedback{Viewed: view})
36 | return err
37 | }
38 |
39 | func (self *Feedback) DeleteFeedbackArray(array []int) error {
40 | _, err := orm.In("id", array).Delete(&Feedback{})
41 | sql := "delete from `feedback` where id in ("
42 | for index, val := range array {
43 | sql += strconv.Itoa(val)
44 | if index < len(array)-1 {
45 | sql += ","
46 | }
47 | }
48 | sql += ")"
49 | _, err = orm.Exec(sql)
50 | Log.Info("Feedback array: ", array, " deleted")
51 | return err
52 | }
53 |
54 | func (self *Feedback) Info() ([]Feedback, int64, error) {
55 | total, err := orm.UseBool("viewed").MustCols("viewed").Count(self)
56 | var feedback []Feedback
57 | err = orm.UseBool("viewed").MustCols("viewed").OrderBy("create_date desc").Limit(5, 0).Find(&feedback, self)
58 | return feedback, total, err
59 | }
60 |
61 | func (self *Feedback) SearchByPage() ([]Feedback, int64, error) {
62 | total, err := orm.Count(self)
63 | var feedback []Feedback
64 | err = orm.OrderBy(self.GetSortProperties()[0].Column+" "+self.GetSortProperties()[0].Direction).Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&feedback, self)
65 | return feedback, total, err
66 | }
67 |
--------------------------------------------------------------------------------
/model/visit.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 |
6 | "time"
7 | )
8 |
9 | type Visit struct {
10 | SessionId string `xorm:"varchar(60) pk not null "`
11 | Ip string `xorm:"varchar(15) null"`
12 | User User `json:"user_id" xorm:"user_id"`
13 | CreateDate time.Time `xorm:"datetime created"`
14 | Page `xorm:"-"`
15 | }
16 |
17 | type Statistics struct {
18 | TotalCount int
19 | MonthCount int
20 | DayCount int
21 | }
22 |
23 | func (self *Visit) Exist() (exist bool) {
24 | exist, err := orm.Get(self)
25 | PanicIf(err)
26 | return
27 | }
28 |
29 | func (self *Visit) ExistVisit() (exist bool) {
30 | exist, err := orm.Get(&Visit{SessionId: self.SessionId})
31 | PanicIf(err)
32 | return
33 | }
34 |
35 | func (self *Visit) GetVisit() (visit Visit) {
36 | _, err := orm.Id(self.SessionId).Get(&visit)
37 | PanicIf(err)
38 | return
39 | }
40 |
41 | func (self *Visit) Insert() error {
42 | _, err := orm.InsertOne(self)
43 | Log.Info("Visit ", self.SessionId, " inserted")
44 | return err
45 | }
46 |
47 | func (self *Visit) Update() error {
48 | _, err := orm.Id(self.SessionId).Update(self)
49 | Log.Info("Visit ", self.SessionId, " updated")
50 | return err
51 | }
52 |
53 | func (self *Visit) Delete() error {
54 | _, err := orm.Delete(self)
55 | Log.Info("Visit ", self.SessionId, " deleted")
56 | return err
57 | }
58 |
59 | func (self *Visit) SearchByPage() ([]Visit, int, error) {
60 | total, err := orm.Count(self)
61 | var visit []Visit
62 | err = orm.OrderBy(self.GetSortProperties()[0].Column+" "+self.GetSortProperties()[0].Direction).Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&visit, self)
63 | return visit, int(total), err
64 | }
65 |
66 | func (self *Visit) GetStatistics() (stat Statistics) {
67 |
68 | total, err := orm.Count(&Visit{})
69 | PanicIf(err)
70 | stat.TotalCount = int(total)
71 |
72 | monthCount, err := orm.Where("date_format(create_date,'%Y-%m')=date_format(now(),'%Y-%m')").Count(&Visit{})
73 | PanicIf(err)
74 | stat.MonthCount = int(monthCount)
75 |
76 | dayCount, err := orm.Where(" datediff(create_date,NOW()) = 0").Count(&Visit{})
77 | PanicIf(err)
78 | stat.DayCount = int(dayCount)
79 |
80 | return
81 | }
82 |
--------------------------------------------------------------------------------
/templates/profile/preferences.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.preferences"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{template "layout/back_nav" .}}
29 | {{template "layout/left" .}}
30 |
31 |
32 |
38 | {{template "layout/message" .}}
39 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/handler/linkHandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/go-martini/martini"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 | "github.com/easykoo/go-blog/middleware"
8 | "github.com/easykoo/go-blog/model"
9 |
10 | "encoding/json"
11 | )
12 |
13 | func AllLink(ctx *middleware.Context) {
14 | switch ctx.R.Method {
15 | case "POST":
16 | link := new(model.Link)
17 | link.SetPageActive(true)
18 | link.SetPageSize(ParseInt(ctx.R.FormValue("iDisplayLength")))
19 | link.SetDisplayStart(ParseInt(ctx.R.FormValue("iDisplayStart")))
20 | columnNum := ctx.R.FormValue("iSortCol_0")
21 | sortColumn := ctx.R.FormValue("mDataProp_" + columnNum)
22 | link.AddSortProperty(sortColumn, ctx.R.FormValue("sSortDir_0"))
23 | linkArray, total, err := link.SearchByPage()
24 | PanicIf(err)
25 | ctx.Set("aaData", linkArray)
26 | ctx.Set("iTotalDisplayRecords", total)
27 | ctx.Set("iTotalRecords", total)
28 | ctx.JSON(200, ctx.Response)
29 | default:
30 | ctx.HTML(200, "link/allLink", ctx)
31 | }
32 | }
33 |
34 | func InsertLink(ctx *middleware.Context, link model.Link) {
35 | switch ctx.R.Method {
36 | case "POST":
37 | err := link.Insert()
38 | PanicIf(err)
39 | ctx.Set("success", true)
40 | ctx.Set("message", Translate(ctx.S.Get("Lang").(string), "message.send.success"))
41 | ctx.Redirect("/link/all")
42 | default:
43 | ctx.HTML(200, "link/edit", ctx)
44 | }
45 | }
46 |
47 | func DeleteLink(ctx *middleware.Context, params martini.Params) {
48 | id := params["id"]
49 | link := new(model.Link)
50 | link.Id = ParseInt(id)
51 | err := link.Delete()
52 | PanicIf(err)
53 | ctx.Set("success", true)
54 | ctx.JSON(200, ctx.Response)
55 | }
56 |
57 | func DeleteLinkArray(ctx *middleware.Context) {
58 | linkArray := ctx.R.FormValue("linkArray")
59 | link := new(model.Link)
60 | var res []int
61 | json.Unmarshal([]byte(linkArray), &res)
62 | err := link.DeleteLinkArray(res)
63 | PanicIf(err)
64 | ctx.Set("success", true)
65 | ctx.JSON(200, ctx.Response)
66 | }
67 |
68 | func EditLink(ctx *middleware.Context, params martini.Params) {
69 | id := params["id"]
70 | link := new(model.Link)
71 | link.Id = ParseInt(id)
72 | err := link.GetLink()
73 | PanicIf(err)
74 | ctx.Set("Link", link)
75 |
76 | ctx.HTML(200, "link/edit", ctx)
77 | }
78 |
--------------------------------------------------------------------------------
/handler/feedbackHandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/go-martini/martini"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 | "github.com/easykoo/go-blog/middleware"
8 | "github.com/easykoo/go-blog/model"
9 |
10 | "encoding/json"
11 | )
12 |
13 | func FeedbackInfo(ctx *middleware.Context) {
14 | feedback := new(model.Feedback)
15 | feedback.Viewed = false
16 | feedbackArray, count, err := feedback.Info()
17 | PanicIf(err)
18 | ctx.Set("Array", feedbackArray)
19 | ctx.Set("Count", count)
20 | ctx.JSON(200, ctx.Response)
21 | }
22 |
23 | func AllFeedback(ctx *middleware.Context) {
24 | switch ctx.R.Method {
25 | case "POST":
26 | feedback := new(model.Feedback)
27 | feedback.SetPageActive(true)
28 | feedback.SetPageSize(ParseInt(ctx.R.FormValue("iDisplayLength")))
29 | feedback.SetDisplayStart(ParseInt(ctx.R.FormValue("iDisplayStart")))
30 | columnNum := ctx.R.FormValue("iSortCol_0")
31 | sortColumn := ctx.R.FormValue("mDataProp_" + columnNum)
32 | feedback.AddSortProperty(sortColumn, ctx.R.FormValue("sSortDir_0"))
33 | feedbackArray, total, err := feedback.SearchByPage()
34 | PanicIf(err)
35 | ctx.Set("aaData", feedbackArray)
36 | ctx.Set("iTotalDisplayRecords", total)
37 | ctx.Set("iTotalRecords", total)
38 | ctx.JSON(200, ctx.Response)
39 | default:
40 | ctx.HTML(200, "feedback/allFeedback", ctx)
41 | }
42 | }
43 |
44 | func DeleteFeedback(ctx *middleware.Context, params martini.Params) {
45 | id := params["id"]
46 | feedback := new(model.Feedback)
47 | feedback.Id = ParseInt(id)
48 | err := feedback.Delete()
49 | PanicIf(err)
50 | ctx.Set("success", true)
51 | ctx.JSON(200, ctx.Response)
52 | }
53 |
54 | func DeleteFeedbackArray(ctx *middleware.Context) {
55 | feedbackArray := ctx.R.FormValue("feedbackArray")
56 | feedback := new(model.Feedback)
57 | var res []int
58 | json.Unmarshal([]byte(feedbackArray), &res)
59 | err := feedback.DeleteFeedbackArray(res)
60 | PanicIf(err)
61 | ctx.Set("success", true)
62 | ctx.JSON(200, ctx.Response)
63 | }
64 |
65 | func ViewFeedback(ctx *middleware.Context, params martini.Params) {
66 | id := params["id"]
67 | feedback := new(model.Feedback)
68 | feedback.Id = ParseInt(id)
69 | err := feedback.SetViewed(true)
70 | PanicIf(err)
71 | ctx.Set("success", true)
72 | ctx.JSON(200, ctx.Response)
73 | }
74 |
--------------------------------------------------------------------------------
/templates/layout/blog_side.html:
--------------------------------------------------------------------------------
1 | {{$session := .Session}}
2 | {{$lang := .Session.Lang}}
3 |
4 |
16 |
17 | {{with .DbUtil.GetHotBlog}}
18 |
19 |
{{tsl $lang "label.hot.blog"}}
20 |
21 | {{range .}}
22 |
28 | {{end}}
29 |
30 | {{end}}
31 |
32 | {{with .DbUtil.GetRecentComments}}
33 |
34 |
{{tsl $lang "label.latest.comments"}}
35 |
36 | {{range .}}
37 |
49 | {{end}}
50 |
51 | {{end}}
52 |
53 | {{with .Response.Tags}}
54 |
55 |
{{tsl $lang "label.tags"}}
56 |
57 |
64 |
65 | {{end}}
66 |
--------------------------------------------------------------------------------
/public/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=s.elements;return"string"==typeof a?a.split(" "):a}function e(a){var b=r[a[p]];return b||(b={},q++,a[p]=q,r[q]=b),b}function f(a,c,d){if(c||(c=b),k)return c.createElement(a);d||(d=e(c));var f;return f=d.cache[a]?d.cache[a].cloneNode():o.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!f.canHaveChildren||n.test(a)||f.tagUrn?f:d.frag.appendChild(f)}function g(a,c){if(a||(a=b),k)return a.createDocumentFragment();c=c||e(a);for(var f=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)f.createElement(h[g]);return f}function h(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return s.shivMethods?f(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(s,b.frag)}function i(a){a||(a=b);var d=e(a);return!s.shivCSS||j||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),k||h(a,d),a}var j,k,l="3.7.0",m=a.html5||{},n=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,o=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,p="_html5shiv",q=0,r={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",j="hidden"in a,k=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){j=!0,k=!0}}();var s={elements:m.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:l,shivCSS:m.shivCSS!==!1,supportsUnknownElements:k,shivMethods:m.shivMethods!==!1,type:"default",shivDocument:i,createElement:f,createDocumentFragment:g};a.html5=s,i(b)}(this,document);
--------------------------------------------------------------------------------
/model/page.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | . "github.com/easykoo/go-blog/common"
5 | )
6 |
7 | type SortProperty struct {
8 | Column string
9 | Direction string
10 | }
11 |
12 | type Page struct {
13 | pageActive bool
14 | displayStart int
15 | pageNo int
16 | pageSize int
17 | totalRecord int
18 | totalPage int
19 | sortProperties []*SortProperty
20 | Result interface{}
21 | }
22 |
23 | func (self *Page) GetDisplayStart() int {
24 | return self.displayStart
25 | }
26 |
27 | func (self *Page) GetPageNo() int {
28 | return self.pageNo
29 | }
30 |
31 | func (self *Page) GetPreviousPageNo() int {
32 | if self.pageNo <= 1 {
33 | return 1
34 | }
35 | return self.pageNo - 1
36 | }
37 |
38 | func (self *Page) GetNextPageNo() int {
39 | if self.pageNo >= self.totalPage {
40 | return self.totalPage
41 | }
42 | return self.pageNo + 1
43 | }
44 |
45 | func (self *Page) GetPageSize() int {
46 | return self.pageSize
47 | }
48 |
49 | func (self *Page) GetTotalRecord() int {
50 | return self.totalRecord
51 | }
52 |
53 | func (self *Page) GetTotalPage() int {
54 | return self.totalPage
55 | }
56 |
57 | func (self *Page) GetSortProperties() []*SortProperty {
58 | return self.sortProperties
59 | }
60 |
61 | func (self *Page) SetPageActive(active bool) {
62 | self.pageActive = active
63 | }
64 |
65 | func (self *Page) SetPageSize(pageSize int) {
66 | self.pageSize = pageSize
67 | }
68 |
69 | func (self *Page) SetDisplayStart(displayStart int) {
70 | self.initIf()
71 | if ((displayStart + 1) / self.pageSize) < 1 {
72 | self.pageNo = 1
73 | } else {
74 | self.pageNo = ((displayStart + 1) / self.pageSize) + 1
75 | }
76 | self.displayStart = displayStart
77 | }
78 |
79 | func (self *Page) SetPageNo(pageNo int) {
80 | if pageNo < 1 {
81 | pageNo = 1
82 | }
83 | self.pageNo = pageNo
84 | self.displayStart = (pageNo - 1) * self.pageSize
85 | }
86 |
87 | func (self *Page) SetTotalRecord(totalRecord int) {
88 | self.initIf()
89 | self.totalRecord = totalRecord
90 | var totalPage int
91 | if totalRecord%self.pageSize == 0 {
92 | totalPage = totalRecord / self.pageSize
93 | } else {
94 | totalPage = totalRecord/self.pageSize + 1
95 | }
96 | self.totalPage = totalPage
97 | if self.pageNo > totalPage {
98 | self.pageNo = totalPage
99 | }
100 | }
101 |
102 | func (self *Page) AddSortProperty(column string, direction string) {
103 | self.sortProperties = append(self.sortProperties, &SortProperty{Column: Atoa(column), Direction: direction})
104 | }
105 |
106 | func (self *Page) initIf() {
107 | if self.pageNo == 0 {
108 | self.pageNo = 1
109 | }
110 | if self.pageSize == 0 {
111 | self.pageSize = 10
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/public/codemirror/formatting.min.js:
--------------------------------------------------------------------------------
1 | (function(){function e(e){for(var t=[/for\s*?\((.*?)\)/,/\"(.*?)(\"|$)/,/\'(.*?)(\'|$)/,/\/\*(.*?)(\*\/|$)/,/\/\/.*/],n=[],i=0;t.length>i;i++)for(var a=0;e.length>a;){var r=e.substr(a).match(t[i]);if(null==r)break;n.push({start:a+r.index,end:a+r.index+r[0].length}),a+=r.index+Math.max(1,r[0].length)}return n.sort(function(e,t){return e.start-t.start}),n}function t(e,t){return CodeMirror.innerMode(e.getMode(),e.getTokenAt(t).state).mode}function n(e,t,n,i){var a=e.getMode(),r=e.getLine(t);if(null==i&&(i=r.length),!a.innerMode)return[{from:n,to:i,mode:a}];var o=e.getTokenAt({line:t,ch:n}).state,s=CodeMirror.innerMode(a,o).mode,l=[],c=new CodeMirror.StringStream(r);for(c.pos=c.start=n;;){a.token(c,o);var u=CodeMirror.innerMode(a,o).mode;if(u!=s){var d=c.start;"xml"==s.name&&">"==r.charAt(c.pos-1)&&(d=c.pos),l.push({from:n,to:d,mode:s}),n=d,s=u}if(c.pos>=i)break;c.start=c.pos}return i>n&&l.push({from:n,to:i,mode:s}),l}CodeMirror.extendMode("css",{commentStart:"/*",commentEnd:"*/",wordWrapChars:[";","\\{","\\}"],autoFormatLineBreaks:function(e){return e.replace(RegExp("(;|\\{|\\})([^\r\n])","g"),"$1\n$2")}}),CodeMirror.extendMode("javascript",{commentStart:"/*",commentEnd:"*/",wordWrapChars:[";","\\{","\\}"],autoFormatLineBreaks:function(t){var n=0,i=this.jsonMode?function(e){return e.replace(/([,{])/g,"$1\n").replace(/}/g,"\n}")}:function(e){return e.replace(/(;|\{|\})([^\r\n;])/g,"$1\n$2")},a=e(t),r="";if(null!=a){for(var o=0;a.length>o;o++)a[o].start>n&&(r+=i(t.substring(n,a[o].start)),n=a[o].start),n>=a[o].start&&a[o].end>=n&&(r+=t.substring(n,a[o].end),n=a[o].end);t.length>n&&(r+=i(t.substr(n)))}else r=i(t);return r.replace(/^\n*|\n*$/,"")}}),CodeMirror.extendMode("xml",{commentStart:"",wordWrapChars:[">"],autoFormatLineBreaks:function(e){for(var t=e.split("\n"),n=RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)"),i=RegExp("<","g"),a=RegExp("(>)([^\r\n])","g"),r=0;t.length>r;r++){var o=t[r].match(n);null!=o&&o.length>3&&(t[r]=o[1]+o[2].replace(i,"\n$&").replace(a,"$1\n$2")+o[3])}return t.join("\n")}}),CodeMirror.defineExtension("commentRange",function(e,n,i){var a=t(this,n),r=this;this.operation(function(){if(e)r.replaceRange(a.commentEnd,i),r.replaceRange(a.commentStart,n),n.line==i.line&&n.ch==i.ch&&r.setCursor(n.line,n.ch+a.commentStart.length);else{var t=r.getRange(n,i),o=t.indexOf(a.commentStart),s=t.lastIndexOf(a.commentEnd);o>-1&&s>-1&&s>o&&(t=t.substr(0,o)+t.substring(o+a.commentStart.length,s)+t.substr(s+a.commentEnd.length)),r.replaceRange(t,n,i)}})}),CodeMirror.defineExtension("autoIndentRange",function(e,t){var n=this;this.operation(function(){for(var i=e.line;t.line>=i;i++)n.indentLine(i,"smart")})}),CodeMirror.defineExtension("autoFormatRange",function(e,t){var i=this;i.operation(function(){for(var a=e.line,r=t.line;r>=a;++a){for(var o={line:a,ch:a==e.line?e.ch:0},s={line:a,ch:a==r?t.ch:null},l=n(i,a,o.ch,s.ch),c="",u=i.getRange(o,s),d=0;l.length>d;++d){var p=l.length>1?u.slice(l[d].from,l[d].to):u;c&&(c+="\n"),c+=l[d].mode.autoFormatLineBreaks?l[d].mode.autoFormatLineBreaks(p):u}if(c!=u){for(var m=0,h=c.indexOf("\n");-1!=h;h=c.indexOf("\n",h+1),++m);i.replaceRange(c,o,s),a+=m,r+=m}}for(var a=e.line+1;r>=a;++a)i.indentLine(a,"smart");i.setSelection(e,i.getCursor(!1))})})})();
--------------------------------------------------------------------------------
/templates/user/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.sign.in"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 | {{template "layout/front_nav" .}}
27 |
28 |
29 |
30 |
31 |
{{tsl .Session.Lang "label.please.sign.in"}}
32 |
33 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/templates/user/register.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.sign.up"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 | {{template "layout/front_nav" .}}
27 |
28 |
29 |
30 |
31 |
{{tsl .Session.Lang "label.please.sign.up"}}
32 |
33 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 | {{template "layout/front_nav" .}}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
Business Name or Tagline
37 |
38 |
This is a template that is great for small businesses. It doesn't have too much fancy flare to it, but it
39 | makes a great use of the standard Bootstrap core components. Feel free to use this template for any
40 | project you want!
41 |
Call to Action!
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | This is a well that is a great spot for a business tagline or phone number for easy access!
51 |
52 |
53 |
54 |
55 |
56 |
57 |
Heading 1
58 |
59 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sollicitudin auctor quam ac tempor. Cras
60 | a ante sed libero mollis sodales. Praesent fringilla, neque ut ultrices faucibus, dolor eros ultrices
61 | neque, nec bibendum arcu ipsum eget justo.
62 |
More Info
63 |
64 |
65 |
Heading 2
66 |
67 |
Phasellus vestibulum sagittis purus laoreet varius. Pellentesque malesuada malesuada mattis. Aliquam sed
68 | porta nisi, eget suscipit dolor. Nam ipsum sapien, rhoncus eu leo eu, ultricies pellentesque tellus.
69 |
More Info
70 |
71 |
72 |
Heading 3
73 |
74 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sollicitudin auctor quam ac tempor. Cras
75 | a ante sed libero mollis sodales. Praesent fringilla, neque ut ultrices faucibus, dolor eros ultrices
76 | neque, nec bibendum arcu ipsum eget justo.
77 |
More Info
78 |
79 |
80 |
81 |
82 | {{template "layout/footer" .}}
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | x64/
49 | build/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # MSTest test Results
54 | [Tt]est[Rr]esult*/
55 | [Bb]uild[Ll]og.*
56 |
57 | *_i.c
58 | *_p.c
59 | *.ilk
60 | *.meta
61 | *.obj
62 | *.pch
63 | *.pdb
64 | *.pgc
65 | *.pgd
66 | *.rsp
67 | *.sbr
68 | *.tlb
69 | *.tli
70 | *.tlh
71 | *.tmp
72 | *.tmp_proj
73 | *.log
74 | *.vspscc
75 | *.vssscc
76 | .builds
77 | *.pidb
78 | *.log
79 | *.scc
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | *.ncrunch*
109 | .*crunch*.local.xml
110 |
111 | # Installshield output folder
112 | [Ee]xpress/
113 |
114 | # DocProject is a documentation generator add-in
115 | DocProject/buildhelp/
116 | DocProject/Help/*.HxT
117 | DocProject/Help/*.HxC
118 | DocProject/Help/*.hhc
119 | DocProject/Help/*.hhk
120 | DocProject/Help/*.hhp
121 | DocProject/Help/Html2
122 | DocProject/Help/html
123 |
124 | # Click-Once directory
125 | publish/
126 |
127 | # Publish Web Output
128 | *.Publish.xml
129 | *.pubxml
130 |
131 | # NuGet Packages Directory
132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
133 | #packages/
134 |
135 | # Windows Azure Build Output
136 | csx
137 | *.build.csdef
138 |
139 | # Windows Store app package directory
140 | AppPackages/
141 |
142 | # Others
143 | sql/
144 | *.Cache
145 | ClientBin/
146 | [Ss]tyle[Cc]op.*
147 | ~$*
148 | *~
149 | *.dbmdl
150 | *.[Pp]ublish.xml
151 | *.pfx
152 | *.publishsettings
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | App_Data/*.mdf
166 | App_Data/*.ldf
167 |
168 | #############
169 | ## Windows detritus
170 | #############
171 |
172 | # Windows image file caches
173 | Thumbs.db
174 | ehthumbs.db
175 |
176 | # Folder config file
177 | Desktop.ini
178 |
179 | # Recycle Bin used on file shares
180 | $RECYCLE.BIN/
181 |
182 | # Mac crap
183 | .DS_Store
184 |
185 |
186 | #############
187 | ## Python
188 | #############
189 |
190 | *.py[co]
191 |
192 | # Packages
193 | *.egg
194 | *.egg-info
195 | dist/
196 | build/
197 | eggs/
198 | parts/
199 | var/
200 | sdist/
201 | develop-eggs/
202 | .installed.cfg
203 |
204 | # Installer logs
205 | pip-log.txt
206 |
207 | # Unit test / coverage reports
208 | .coverage
209 | .tox
210 |
211 | #Translations
212 | *.mo
213 |
214 | #Mr Developer
215 | .mr.developer.cfg
216 |
217 | #Custom
218 | *.exe
219 | *.iml
220 | .idea
221 | go-blog
--------------------------------------------------------------------------------
/public/codemirror/codemirror.min.css:
--------------------------------------------------------------------------------
1 | .CodeMirror{font-family:monospace;height:300px}.CodeMirror-scroll{overflow:auto}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{background-color:white}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999}.CodeMirror div.CodeMirror-cursor{border-left:1px solid black;z-index:3}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor{width:auto;border:0;background:#7e7;z-index:1}.cm-tab{display:inline-block}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable{color:black}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-property{color:black}.cm-s-default .cm-operator{color:black}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-header{color:blue}.cm-s-default .cm-quote{color:#090}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:bold}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-s-default .cm-error{color:#f00}.cm-invalidchar{color:#f00}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{line-height:1;position:relative;overflow:hidden;background:white;color:black}.CodeMirror-scroll{margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;padding-right:30px;height:100%;outline:0;position:relative;-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-sizer{position:relative}.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;padding-bottom:30px;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;-moz-box-sizing:content-box;box-sizing:content-box;padding-bottom:30px;margin-bottom:-32px;display:inline-block;*zoom:1;*display:inline}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-code pre{border-right:30px solid transparent;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.CodeMirror-wrap .CodeMirror-code pre{border-right:0;width:auto}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-measure pre{position:static}.CodeMirror div.CodeMirror-cursor{position:absolute;visibility:hidden;border-right:0;width:0}.CodeMirror-focused div.CodeMirror-cursor{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.CodeMirror span{*vertical-align:text-bottom}@media print{.CodeMirror div.CodeMirror-cursor{visibility:hidden}}
--------------------------------------------------------------------------------
/middleware/memory_store.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gorilla/securecookie"
5 | "github.com/gorilla/sessions"
6 |
7 | . "github.com/easykoo/go-blog/common"
8 |
9 | "encoding/base32"
10 | "net/http"
11 | "strings"
12 | "time"
13 | )
14 |
15 | // MemoryStore ------------------------------------------------------------
16 |
17 | func NewMemoryStore(age int) *MemoryStore {
18 | memoryStore := &MemoryStore{
19 | Codecs: securecookie.CodecsFromPairs([]byte("secret")),
20 | Options: &sessions.Options{
21 | Path: "/",
22 | MaxAge: age, //default 30 minutes
23 | },
24 | Container: make(map[string]*SessionInfo),
25 | }
26 | go memoryStore.CheckMemorySessions()
27 | return memoryStore
28 | }
29 |
30 | type MemoryStore struct {
31 | Codecs []securecookie.Codec
32 | Options *sessions.Options // default configuration
33 | Container map[string]*SessionInfo
34 | }
35 |
36 | type SessionInfo struct {
37 | S *sessions.Session
38 | T time.Time
39 | }
40 |
41 | // Get returns a session for the given name after adding it to the registry.
42 | //
43 | func (s *MemoryStore) Get(r *http.Request, name string) (*sessions.Session, error) {
44 | Log.Info("MemoryStore Get()")
45 | return sessions.GetRegistry(r).Get(s, name)
46 | }
47 |
48 | // New returns a session for the given name without adding it to the registry.
49 | //
50 | func (s *MemoryStore) New(r *http.Request, name string) (*sessions.Session, error) {
51 | session := sessions.NewSession(s, name)
52 | opts := *s.Options
53 | session.Options = &opts
54 | session.IsNew = true
55 | var err error
56 | if c, errCookie := r.Cookie(name); errCookie == nil {
57 | Log.Info("MemoryStore reading cookie")
58 | err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
59 | PanicIf(err)
60 | if err == nil {
61 | Log.Info("MemoryStore read cookie success")
62 | err = s.load(session)
63 | if err == nil {
64 | session.IsNew = false
65 | }
66 | }
67 | }
68 | return session, err
69 | }
70 |
71 | // Save adds a single session to the response.
72 | func (s *MemoryStore) Save(r *http.Request, w http.ResponseWriter,
73 | session *sessions.Session) error {
74 | Log.Info("MemoryStore Save()", session.ID)
75 | if session.ID == "" {
76 | session.ID = strings.TrimRight(
77 | base32.StdEncoding.EncodeToString(
78 | securecookie.GenerateRandomKey(32)), "=")
79 | }
80 | if err := s.save(session); err != nil {
81 | return err
82 | }
83 | encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
84 | s.Codecs...)
85 | if err != nil {
86 | return err
87 | }
88 | http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
89 | return nil
90 | }
91 |
92 | // save writes encoded session.Values to a file.
93 | func (s *MemoryStore) save(session *sessions.Session) error {
94 | Log.Info("MemoryStore save()")
95 | s.Container[session.ID] = &SessionInfo{S: session, T: time.Now()}
96 | return nil
97 | }
98 |
99 | // load reads a file and decodes its content into session.Values.
100 | func (s *MemoryStore) load(session *sessions.Session) error {
101 | Log.Info("MemoryStore load()")
102 | Log.Info("MemoryStore load session: ", session.ID)
103 | if _, ok := s.Container[session.ID]; ok {
104 | Log.Info("MemoryStore load session OK ")
105 | session = s.Container[session.ID].S
106 | Log.Info("MemoryStore load SignedUser: ", session.Values["SignedUser"])
107 | } else {
108 | Log.Info("MemoryStore load session failed ")
109 | }
110 | return nil
111 | }
112 |
113 | func (s *MemoryStore) CheckMemorySessions() {
114 | timer := time.NewTicker(30 * time.Second)
115 | for {
116 | select {
117 | case <-timer.C:
118 | go func() {
119 | s.removeMemorySessions()
120 | }()
121 | }
122 | }
123 |
124 | }
125 |
126 | func (s *MemoryStore) removeMemorySessions() {
127 | for sId, sessionInfo := range s.Container {
128 | if (time.Now().Unix() - sessionInfo.T.Unix()) >= int64(s.Options.MaxAge) {
129 | Log.Info(time.Now().Unix() - sessionInfo.T.Unix())
130 | delete(s.Container, sId)
131 | Log.Info("Removed: ", sId)
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/templates/layout/front_nav.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/public/js/respond.min.js:
--------------------------------------------------------------------------------
1 | /*! Respond.js v1.4.2: min/max-width media query polyfill
2 | * Copyright 2014 Scott Jehl
3 | * Licensed under MIT
4 | * http://j.mp/respondjs */
5 |
6 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b 0)
79 | }
80 |
81 | func (self *Context) SetFormErrors(err binding.Errors) {
82 | self.FormErr = err
83 | }
84 |
85 | func (self *Context) JoinFormErrors(err binding.Errors) {
86 | self.init()
87 | for key, val := range err.Fields {
88 | if _, exists := self.FormErr.Fields[key]; !exists {
89 | self.FormErr.Fields[key] = val
90 | }
91 | }
92 | for key, val := range err.Overall {
93 | if _, exists := self.FormErr.Overall[key]; !exists {
94 | self.FormErr.Overall[key] = val
95 | }
96 | }
97 | }
98 |
99 | func (self *Context) AddError(err string) {
100 | self.Errors = append(self.Errors, err)
101 | }
102 |
103 | func (self *Context) AddFieldError(field string, err string) {
104 | self.FormErr.Fields[field] = err
105 | }
106 |
107 | func (self *Context) ClearError() {
108 | self.Errors = self.Errors[:0]
109 |
110 | for key, _ := range self.FormErr.Fields {
111 | if _, exists := self.FormErr.Fields[key]; exists {
112 | delete(self.FormErr.Fields, key)
113 | }
114 | }
115 |
116 | for key, _ := range self.FormErr.Overall {
117 | if _, exists := self.FormErr.Overall[key]; exists {
118 | delete(self.FormErr.Overall, key)
119 | }
120 | }
121 | }
122 |
123 | func (self *Context) HasError() bool {
124 | return self.HasCommonError() || self.HasFieldError() || self.HasOverallError()
125 | }
126 |
127 | func (self *Context) HasCommonError() bool {
128 | return (len(self.Errors) > 0)
129 | }
130 |
131 | func (self *Context) HasFieldError() bool {
132 | return (len(self.FormErr.Fields) > 0)
133 | }
134 |
135 | func (self *Context) HasOverallError() bool {
136 | return (len(self.FormErr.Overall) > 0)
137 | }
138 |
139 | func (self *Context) OverallErrors() map[string]string {
140 | return self.FormErr.Overall
141 | }
142 |
143 | func (self *Context) FieldErrors() map[string]string {
144 | return self.FormErr.Fields
145 | }
146 |
147 | func (self *Context) Session() map[interface{}]interface{} {
148 | return self.S.Values()
149 | }
150 |
151 | func InitContext() martini.Handler {
152 | return func(c martini.Context, s sessions.Session, rnd render.Render, r *http.Request, w http.ResponseWriter) {
153 | ctx := &Context{
154 | Render: rnd,
155 | W: w,
156 | R: r,
157 | C: c,
158 | S: s,
159 | DbUtil: &model.DbUtil{},
160 | }
161 |
162 | lang := s.Get("Lang")
163 | if lang == nil {
164 | s.Set("Lang", Cfg.MustValue("", "locale", "en"))
165 | }
166 |
167 | s.Set("Settings", model.GetSettings())
168 | c.Map(ctx)
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/middleware/db_store.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gorilla/securecookie"
5 | . "github.com/gorilla/sessions"
6 |
7 | . "github.com/easykoo/go-blog/common"
8 | "github.com/easykoo/go-blog/model"
9 |
10 | "encoding/base32"
11 | "net/http"
12 | "strings"
13 | "time"
14 | )
15 |
16 | // DbStore ------------------------------------------------------------
17 |
18 | // NewSessionStore returns a new DbStore.
19 | //
20 | // The path argument is the directory where sessions will be saved. If empty
21 | // it will use os.TempDir().
22 | //
23 | // See NewCookieStore() for a description of the other parameters.
24 | func NewDbStore(age int) *DbStore {
25 | sessionStore := &DbStore{
26 | Codecs: securecookie.CodecsFromPairs([]byte("secret")),
27 | Options: &Options{
28 | Path: "/",
29 | MaxAge: age, //seconds
30 | },
31 | }
32 | go sessionStore.CheckDbSessions()
33 | return sessionStore
34 | }
35 |
36 | // DbStore stores sessions in the filesystem.
37 | //
38 | // It also serves as a referece for custom stores.
39 | //
40 | // This store is still experimental and not well tested. Feedback is welcome.
41 | type DbStore struct {
42 | Codecs []securecookie.Codec
43 | Options *Options // default configuration
44 | }
45 |
46 | // MaxLength restricts the maximum length of new sessions to l.
47 | // If l is 0 there is no limit to the size of a session, use with caution.
48 | // The default for a new DbStore is 4096.
49 | func (s *DbStore) MaxLength(l int) {
50 | for _, c := range s.Codecs {
51 | if codec, ok := c.(*securecookie.SecureCookie); ok {
52 | codec.MaxLength(l)
53 | }
54 | }
55 | }
56 |
57 | // Get returns a session for the given name after adding it to the registry.
58 | //
59 | // See CookieStore.Get().
60 | func (s *DbStore) Get(r *http.Request, name string) (*Session, error) {
61 | return GetRegistry(r).Get(s, name)
62 | }
63 |
64 | // New returns a session for the given name without adding it to the registry.
65 | //
66 | // See CookieStore.New().
67 | func (s *DbStore) New(r *http.Request, name string) (*Session, error) {
68 | session := NewSession(s, name)
69 | opts := *s.Options
70 | session.Options = &opts
71 | session.IsNew = true
72 | var err error
73 | if c, errCookie := r.Cookie(name); errCookie == nil {
74 | err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
75 | PanicIf(err)
76 | if err == nil {
77 | err = s.load(session)
78 | if err == nil {
79 | session.IsNew = false
80 | }
81 | }
82 | }
83 | return session, err
84 | }
85 |
86 | // Save adds a single session to the response.
87 | func (s *DbStore) Save(r *http.Request, w http.ResponseWriter,
88 | session *Session) error {
89 | if session.ID == "" {
90 | session.ID = strings.TrimRight(
91 | base32.StdEncoding.EncodeToString(
92 | securecookie.GenerateRandomKey(32)), "=")
93 | }
94 | if err := s.save(session); err != nil {
95 | return err
96 | }
97 | encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
98 | s.Codecs...)
99 | if err != nil {
100 | return err
101 | }
102 | http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
103 | return nil
104 | }
105 |
106 | // save writes encoded session.Values to db.
107 | func (s *DbStore) save(session *Session) error {
108 | encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
109 | s.Codecs...)
110 | if err != nil {
111 | return err
112 | }
113 | sessionInfo := &model.SessionInfo{Id: session.ID, Content: encoded, Age: session.Options.MaxAge}
114 | if (&model.SessionInfo{Id: session.ID}).Exist() {
115 | sessionInfo.Update()
116 | } else {
117 | sessionInfo.Insert()
118 | }
119 | return nil
120 | }
121 |
122 | // load db and decodes its content into session.Values.
123 | func (s *DbStore) load(session *Session) error {
124 | sessionInfo := (&model.SessionInfo{Id: session.ID}).GetSessionInfo()
125 | if err := securecookie.DecodeMulti(session.Name(), sessionInfo.Content,
126 | &session.Values, s.Codecs...); err != nil {
127 | return err
128 | }
129 | return nil
130 | }
131 |
132 | func (s *DbStore) CheckDbSessions() {
133 | timer := time.NewTicker(1 * time.Minute)
134 | for {
135 | select {
136 | case <-timer.C:
137 | go func() {
138 | s.removeDbSessions()
139 | }()
140 | }
141 | }
142 |
143 | }
144 |
145 | func (s *DbStore) removeDbSessions() {
146 | err := (&model.SessionInfo{}).RemoveExpiredSession()
147 | PanicIf(err)
148 | }
149 |
--------------------------------------------------------------------------------
/templates/blog.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.blog"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 | {{template "layout/front_nav" .}}
27 |
28 |
29 |
30 |
31 |
32 | {{template "layout/blog_side" .}}
33 |
34 |
35 | {{$session := .Session}}
36 | {{range .Response.Blog.Result}}
37 |
38 |
39 | {{.Title}}
40 |
41 | {{if $session.SignedUser}}
42 | {{if equal $session.SignedUser.Id .Author.Id}}
43 |
44 |
45 | {{tsl $session.Lang "label.edit"}}
46 |
47 | {{end}}
48 | {{end}}
49 |
50 |
51 |
52 | {{.Author.FullName}}
53 |
54 |
55 | {{tsl $session.Lang "label.post.on"}}
56 | {{if equal $session.Lang "zh"}}
57 | {{.PublishDate | cnFormatTime}}
58 | {{else}}
59 | {{.PublishDate | formatTime}}
60 | {{end}}
61 |
62 | {{.GetCommentSize}}
63 |
64 | {{.Visit}}
65 |
66 | {{with .GetTags}}
67 |
68 | {{range .}}
69 | {{.Name}}
70 | {{end}}
71 | {{end}}
72 |
73 |
74 |
75 | {{.Summary | unescaped}}
76 |
77 | {{tsl $session.Lang "label.read.more"}}
78 |
79 |
80 |
81 |
82 | {{end}}
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | {{template "layout/footer" .}}
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/public/js/jquery.validate.method.js:
--------------------------------------------------------------------------------
1 | jQuery.validator.addMethod("username", function (value, element) {
2 | var username = /^[a-zA-Z][\w]{3,18}[a-zA-Z0-9]$/;
3 | return this.optional(element) || (username.test(value));
4 | }, "5-20, begin with a letter, end with a letter or number, include letter, numbers and underscore.");
5 | jQuery.validator.addMethod("myPassword", function (value, element) {
6 | return this.optional(element) || value.length >= 6 && value.length <= 20 && /\d/.test(value) && /[a-z]/i.test(value);
7 | }, "6-20, contain at least one number and one letter.");
8 | jQuery.validator.addMethod("fileType", function (value, element, param) {
9 | var fileType = value.substring(value.lastIndexOf(".") + 1).toLowerCase();
10 | return this.optional(element) || $.inArray(fileType, param) != -1;
11 | }, $.validator.format("Invalid picture type."));
12 | jQuery.validator.addMethod("fileSize", function (value, element, param) {
13 | return this.optional(element) || element.files[0].size <= param * 1024;
14 | }, $.validator.format("File size is great then {0}."));
15 | // 字符验证
16 | jQuery.validator.addMethod("stringCheck", function (value, element) {
17 | return this.optional(element) || /^[\u0391-\uFFE5\w]+$/.test(value);
18 | }, "只能包括中文字、英文字母、数字和下划线");
19 | // 身份证号码验证
20 | jQuery.validator.addMethod("isIdCardNo", function (value, element) {
21 | return this.optional(element) || isIdCardNo(value);
22 | }, "请正确输入您的身份证号码");
23 | // 手机号码验证
24 | jQuery.validator.addMethod("isMobile", function (value, element) {
25 | var length = value.length;
26 | var mobile = /^(((13[0-9]{1})|(15[0-9]{1}))+\d{8})$/;
27 | return this.optional(element) || (length == 11 && mobile.test(value));
28 | }, "请正确填写您的手机号码");
29 | // 电话号码验证
30 | jQuery.validator.addMethod("isTel", function (value, element) {
31 | var tel = /^\d{3,4}-?\d{7,9}$/; //电话号码格式010-12345678
32 | return this.optional(element) || (tel.test(value));
33 | }, "请正确填写您的电话号码");
34 | // 联系电话(手机/电话皆可)验证
35 | jQuery.validator.addMethod("isPhone", function (value, element) {
36 | var length = value.length;
37 | var mobile = /^(((13[0-9]{1})|(15[0-9]{1}))+\d{8})$/;
38 | var tel = /^\d{3,4}-?\d{7,9}$/;
39 | return this.optional(element) || (tel.test(value) || mobile.test(value));
40 | }, "请正确填写您的联系电话");
41 | // 邮政编码验证
42 | jQuery.validator.addMethod("isZipCode", function (value, element) {
43 | var tel = /^[0-9]{6}$/;
44 | return this.optional(element) || (tel.test(value));
45 | }, "请正确填写您的邮政编码");
46 | // 手机号码验证
47 | jQuery.validator.addMethod("mobile", function (value, element) {
48 | var length = value.length;
49 | var mobile = /^(((13[0-9]{1})|(15[0-9]{1}))+\d{8})$/
50 | return this.optional(element) || (length == 11 && mobile.test(value));
51 | }, "手机号码格式错误");
52 | // 电话号码验证
53 | jQuery.validator.addMethod("phone", function (value, element) {
54 | var tel = /^(0[0-9]{2,3}\-)?([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$/;
55 | return this.optional(element) || (tel.test(value));
56 | }, "电话号码格式错误");
57 | // 邮政编码验证
58 | jQuery.validator.addMethod("zipCode", function (value, element) {
59 | var tel = /^[0-9]{6}$/;
60 | return this.optional(element) || (tel.test(value));
61 | }, "邮政编码格式错误");
62 | // QQ号码验证
63 | jQuery.validator.addMethod("qq", function (value, element) {
64 | var tel = /^[1-9]\d{4,9}$/;
65 | return this.optional(element) || (tel.test(value));
66 | }, "qq号码格式错误");
67 | // IP地址验证
68 | jQuery.validator.addMethod("ip", function (value, element) {
69 | var ip = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
70 | return this.optional(element) || (ip.test(value) && (RegExp.$1 < 256 && RegExp.$2 < 256 && RegExp.$3 < 256 && RegExp.$4 < 256));
71 | }, "Ip地址格式错误");
72 | // 字母和数字的验证
73 | jQuery.validator.addMethod("chrnum", function (value, element) {
74 | var chrnum = /^([a-zA-Z0-9]+)$/;
75 | return this.optional(element) || (chrnum.test(value));
76 | }, "只能输入数字和字母(字符A-Z, a-z, 0-9)");
77 | // 中文的验证
78 | jQuery.validator.addMethod("chinese", function (value, element) {
79 | var chinese = /^[\u4e00-\u9fa5]+$/;
80 | return this.optional(element) || (chinese.test(value));
81 | }, "只能输入中文");
82 | // 下拉框验证
83 | $.validator.addMethod("selectNone", function (value, element) {
84 | return value == "请选择";
85 | }, "必须选择一项");
86 | // 字节长度验证
87 | jQuery.validator.addMethod("byteRangeLength", function (value, element, param) {
88 | var length = value.length;
89 | for (var i = 0; i < value.length; i++) {
90 | if (value.charCodeAt(i) > 127) {
91 | length++;
92 | }
93 | }
94 | return this.optional(element) || (length >= param[0] && length <= param[1]);
95 | }, $.validator.format("请确保输入的值在{0}-{1}个字节之间(一个中文字算2个字节)"));
--------------------------------------------------------------------------------
/dbscripts/baseData_zh.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM user;
2 | INSERT INTO user (id, username, password, full_name, gender, qq, tel, postcode, address, email, role_id, dept_id, active, locked, create_user, create_date, update_user, update_date, version)
3 | VALUES (1, 'admin', 'b0baee9d279d34fa1dfd71aadb908c3f', 'Admin', 1, 111111, '11122233344', '123456', '自由大道1号',
4 | 'admin@admin.com', 1, 1, 1, 0, 'SYSTEM', now(), 'SYSTEM', now(), 1);
5 |
6 | DELETE FROM role;
7 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
8 | VALUES (1, '管理员', 'SYSTEM', now(), 'SYSTEM', now());
9 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
10 | VALUES (2, '经理', 'SYSTEM', now(), 'SYSTEM', now());
11 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
12 | VALUES (3, '员工', 'SYSTEM', now(), 'SYSTEM', now());
13 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
14 | VALUES (4, '用户', 'SYSTEM', now(), 'SYSTEM', now());
15 |
16 | DELETE FROM dept;
17 | INSERT INTO dept (id, description, create_user, create_date, update_user, update_date)
18 | VALUES (1, '默认', 'SYSTEM', now(), 'SYSTEM', now());
19 |
20 | DELETE FROM module;
21 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
22 | VALUES (1, 'Admin', 'SYSTEM', now(), 'SYSTEM', now());
23 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
24 | VALUES (2, 'Account', 'SYSTEM', now(), 'SYSTEM', now());
25 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
26 | VALUES (3, 'Feedback', 'SYSTEM', now(), 'SYSTEM', now());
27 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
28 | VALUES (4, 'News', 'SYSTEM', now(), 'SYSTEM', now());
29 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
30 | VALUES (5, 'Product', 'SYSTEM', now(), 'SYSTEM', now());
31 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
32 | VALUES (6, 'Blog', 'SYSTEM', now(), 'SYSTEM', now());
33 |
34 | DELETE FROM privilege;
35 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
36 | VALUES (1, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
37 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
38 | VALUES (2, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
39 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
40 | VALUES (2, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
41 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
42 | VALUES (3, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
43 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
44 | VALUES (3, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
45 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
46 | VALUES (3, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
47 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
48 | VALUES (4, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
49 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
50 | VALUES (4, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
51 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
52 | VALUES (4, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
53 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
54 | VALUES (5, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
55 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
56 | VALUES (5, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
57 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
58 | VALUES (6, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
59 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
60 | VALUES (6, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
61 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
62 | VALUES (6, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
63 |
64 | DELETE FROM category;
65 | INSERT INTO category (id, description, parent_id, create_user, create_date, update_user, update_date)
66 | VALUES (1, '默认', 0, 'SYSTEM', now(), 'SYSTEM', now());
67 |
68 | DELETE FROM settings;
69 | INSERT INTO settings (id, app_name, owner_id, about, create_user, create_date, update_user, update_date)
70 | VALUES (1, 'Easy Go', 1, null, 'SYSTEM', now(), 'SYSTEM', now());
71 |
--------------------------------------------------------------------------------
/templates/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.about.us"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 | {{with .Session.SignedUser}}
25 | {{if privilege . 1}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | {{end}}
36 | {{end}}
37 |
38 |
39 |
40 |
41 |
42 | {{template "layout/front_nav" .}}
43 |
44 |
45 |
75 |
76 | {{template "layout/footer" .}}
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/public/codemirror/xml.min.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("xml",function(e,t){function f(e,t){function n(n){return t.tokenize=n,n(e,t)}var r=e.next();if(r=="<"){if(e.eat("!"))return e.eat("[")?e.match("CDATA[")?n(h("atom","]]>")):null:e.match("--")?n(h("comment","-->")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),n(p(1))):null;if(e.eat("?"))return e.eatWhile(/[\w\._\-]/),t.tokenize=h("meta","?>"),"meta";var i=e.eat("/");u="";var s;while(s=e.eat(/[^\s\u00a0=<>\"\'\/?]/))u+=s;return u?(a=i?"closeTag":"openTag",t.tokenize=l,"tag"):"tag error"}if(r=="&"){var o;return e.eat("#")?e.eat("x")?o=e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):o=e.eatWhile(/[\d]/)&&e.eat(";"):o=e.eatWhile(/[\w\.\-:]/)&&e.eat(";"),o?"atom":"error"}return e.eatWhile(/[^&<]/),null}function l(e,t){var n=e.next();if(n==">"||n=="/"&&e.eat(">"))return t.tokenize=f,a=n==">"?"endTag":"selfcloseTag","tag";if(n=="=")return a="equals",null;if(n=="<"){t.tokenize=f;var r=t.tokenize(e,t);return r?r+" error":"error"}return/[\'\"]/.test(n)?(t.tokenize=c(n),t.stringStartCol=e.column(),t.tokenize(e,t)):(e.eatWhile(/[^\s\u00a0=<>\"\']/),"word")}function c(e){var t=function(t,n){while(!t.eol())if(t.next()==e){n.tokenize=l;break}return"string"};return t.isInAttribute=!0,t}function h(e,t){return function(n,r){while(!n.eol()){if(n.match(t)){r.tokenize=f;break}n.next()}return e}}function p(e){return function(t,n){var r;while((r=t.next())!=null){if(r=="<")return n.tokenize=p(e+1),n.tokenize(t,n);if(r==">"){if(e==1){n.tokenize=f;break}return n.tokenize=p(e-1),n.tokenize(t,n)}}return"meta"}}function g(){for(var e=arguments.length-1;e>=0;e--)d.cc.push(arguments[e])}function y(){return g.apply(null,arguments),!0}function b(e,t){var n=s.doNotIndent.hasOwnProperty(e)||d.context&&d.context.noIndent;d.context={prev:d.context,tagName:e,indent:d.indented,startOfLine:t,noIndent:n}}function w(){d.context&&(d.context=d.context.prev)}function E(e){if(e=="openTag")return d.tagName=u,d.tagStart=v.column(),y(N,S(d.startOfLine));if(e=="closeTag"){var t=!1;return d.context?d.context.tagName!=u&&(s.implicitlyClosed.hasOwnProperty(d.context.tagName.toLowerCase())&&w(),t=!d.context||d.context.tagName!=u):t=!0,t&&(m="error"),y(x(t))}return y()}function S(e){return function(t){var n=d.tagName;return d.tagName=d.tagStart=null,t=="selfcloseTag"||t=="endTag"&&s.autoSelfClosers.hasOwnProperty(n.toLowerCase())?(T(n.toLowerCase()),y()):t=="endTag"?(T(n.toLowerCase()),b(n,e),y()):y()}}function x(e){return function(t){return e&&(m="error"),t=="endTag"?(w(),y()):(m="error",y(arguments.callee))}}function T(e){var t;for(;;){if(!d.context)return;t=d.context.tagName.toLowerCase();if(!s.contextGrabbers.hasOwnProperty(t)||!s.contextGrabbers[t].hasOwnProperty(e))return;w()}}function N(e){return e=="word"?(m="attribute",y(C,N)):e=="endTag"||e=="selfcloseTag"?g():(m="error",y(N))}function C(e){if(e=="equals")return y(k,N);if(!s.allowMissing)m="error";else if(e=="word")return m="attribute",y(C,N);return e=="endTag"||e=="selfcloseTag"?g():y()}function k(e){return e=="string"?y(L):e=="word"&&s.allowUnquoted?(m="string",y()):(m="error",e=="endTag"||e=="selfCloseTag"?g():y())}function L(e){return e=="string"?y(L):g()}var n=e.indentUnit,r=t.multilineTagIndentFactor||1,i=t.multilineTagIndentPastTag||!0,s=t.htmlMode?{autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0}:{autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1},o=t.alignCDATA,u,a,d,v,m;return{startState:function(){return{tokenize:f,cc:[],indented:0,startOfLine:!0,tagName:null,tagStart:null,context:null}},token:function(e,t){!t.tagName&&e.sol()&&(t.startOfLine=!0,t.indented=e.indentation());if(e.eatSpace())return null;m=a=u=null;var n=t.tokenize(e,t);t.type=a;if((n||a)&&n!="comment"){d=t,v=e;for(;;){var r=t.cc.pop()||E;if(r(a||n))break}}return t.startOfLine=!1,m&&(n=m=="error"?n+" error":m),n},indent:function(e,t,s){var u=e.context;if(e.tokenize.isInAttribute)return e.stringStartCol+1;if(e.tokenize!=l&&e.tokenize!=f||u&&u.noIndent)return s?s.match(/^(\s*)/)[0].length:0;if(e.tagName)return i?e.tagStart+e.tagName.length+2:e.tagStart+n*r;if(o&&/",configuration:t.htmlMode?"html":"xml",helperType:t.htmlMode?"html":"xml"}}),CodeMirror.defineMIME("text/xml","xml"),CodeMirror.defineMIME("application/xml","xml"),CodeMirror.mimeModes.hasOwnProperty("text/html")||CodeMirror.defineMIME("text/html",{name:"xml",htmlMode:!0});
--------------------------------------------------------------------------------
/dbscripts/baseData.sql:
--------------------------------------------------------------------------------
1 | DELETE FROM user;
2 | INSERT INTO user (id, username, password, full_name, gender, qq, tel, postcode, address, email, role_id, dept_id, active, locked, create_user, create_date, update_user, update_date, version)
3 | VALUES (1, 'admin', 'b0baee9d279d34fa1dfd71aadb908c3f', 'Admin', 1, 111111, '11122233344', '123456', '自由大道1号',
4 | 'admin@admin.com', 1, 1, 1, 0, 'SYSTEM', now(), 'SYSTEM', now(), 1);
5 |
6 | DELETE FROM role;
7 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
8 | VALUES (1, 'Admin', 'SYSTEM', now(), 'SYSTEM', now());
9 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
10 | VALUES (2, 'Manager', 'SYSTEM', now(), 'SYSTEM', now());
11 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
12 | VALUES (3, 'Employee', 'SYSTEM', now(), 'SYSTEM', now());
13 | INSERT INTO role (id, description, create_user, create_date, update_user, update_date)
14 | VALUES (4, 'User', 'SYSTEM', now(), 'SYSTEM', now());
15 |
16 | DELETE FROM dept;
17 | INSERT INTO dept (id, description, create_user, create_date, update_user, update_date)
18 | VALUES (1, 'Default', 'SYSTEM', now(), 'SYSTEM', now());
19 |
20 | DELETE FROM module;
21 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
22 | VALUES (1, 'Admin', 'SYSTEM', now(), 'SYSTEM', now());
23 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
24 | VALUES (2, 'Account', 'SYSTEM', now(), 'SYSTEM', now());
25 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
26 | VALUES (3, 'Feedback', 'SYSTEM', now(), 'SYSTEM', now());
27 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
28 | VALUES (4, 'News', 'SYSTEM', now(), 'SYSTEM', now());
29 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
30 | VALUES (5, 'Product', 'SYSTEM', now(), 'SYSTEM', now());
31 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
32 | VALUES (6, 'Blog', 'SYSTEM', now(), 'SYSTEM', now());
33 | INSERT INTO module (id, description, create_user, create_date, update_user, update_date)
34 | VALUES (7, 'Link', 'SYSTEM', now(), 'SYSTEM', now());
35 |
36 | DELETE FROM privilege;
37 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
38 | VALUES (1, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
39 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
40 | VALUES (2, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
41 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
42 | VALUES (2, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
43 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
44 | VALUES (3, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
45 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
46 | VALUES (3, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
47 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
48 | VALUES (3, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
49 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
50 | VALUES (4, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
51 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
52 | VALUES (4, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
53 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
54 | VALUES (4, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
55 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
56 | VALUES (5, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
57 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
58 | VALUES (5, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
59 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
60 | VALUES (6, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
61 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
62 | VALUES (6, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
63 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
64 | VALUES (6, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
65 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
66 | VALUES (7, 1, 1, 'SYSTEM', now(), 'SYSTEM', now());
67 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
68 | VALUES (7, 2, 1, 'SYSTEM', now(), 'SYSTEM', now());
69 | INSERT INTO privilege (module_id, role_id, dept_id, create_user, create_date, update_user, update_date)
70 | VALUES (7, 3, 1, 'SYSTEM', now(), 'SYSTEM', now());
71 |
72 | DELETE FROM category;
73 | INSERT INTO category (id, description, parent_id, create_user, create_date, update_user, update_date)
74 | VALUES (1, 'Default', 0, 'SYSTEM', now(), 'SYSTEM', now());
75 |
76 | DELETE FROM settings;
77 | INSERT INTO settings (id, app_name, owner_id, about, create_user, create_date, update_user, update_date)
78 | VALUES (1, 'Easy Go', 1, null, 'SYSTEM', now(), 'SYSTEM', now());
79 |
--------------------------------------------------------------------------------
/public/js/jquery.easing.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
3 | *
4 | * Uses the built in easing capabilities added In jQuery 1.1
5 | * to offer multiple easing options
6 | *
7 | * TERMS OF USE - EASING EQUATIONS
8 | *
9 | * Open source under the BSD License.
10 | *
11 | * Copyright © 2001 Robert Penner
12 | * All rights reserved.
13 | *
14 | * TERMS OF USE - jQuery Easing
15 | *
16 | * Open source under the BSD License.
17 | *
18 | * Copyright © 2008 George McGinley Smith
19 | * All rights reserved.
20 | *
21 | * Redistribution and use in source and binary forms, with or without modification,
22 | * are permitted provided that the following conditions are met:
23 | *
24 | * Redistributions of source code must retain the above copyright notice, this list of
25 | * conditions and the following disclaimer.
26 | * Redistributions in binary form must reproduce the above copyright notice, this list
27 | * of conditions and the following disclaimer in the documentation and/or other materials
28 | * provided with the distribution.
29 | *
30 | * Neither the name of the author nor the names of contributors may be used to endorse
31 | * or promote products derived from this software without specific prior written permission.
32 | *
33 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
34 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
35 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
36 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
39 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 | * OF THE POSSIBILITY OF SUCH DAMAGE.
42 | *
43 | */
44 | jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g= 60*30 {
193 | Log.Info(time.Now().Unix() - f.ModTime().Unix())
194 | os.Remove(f.Name())
195 | Log.Info("Removed: ", f.Name())
196 | }
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/templates/link/edit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.add.link"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{template "layout/back_nav" .}}
29 | {{template "layout/left" .}}
30 |
31 |
32 |
38 | {{template "layout/message" .}}
39 |
40 |
41 |
43 |
44 |
45 |
46 |
57 |
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/easykoo/binding"
5 |
6 | . "github.com/easykoo/go-blog/common"
7 |
8 | "net/http"
9 | "regexp"
10 | "strconv"
11 | "time"
12 | )
13 |
14 | type User struct {
15 | Id int `form:"userId" xorm:"int(11) pk not null autoincr"`
16 | Username string `form:"username" xorm:"varchar(20) not null"`
17 | Password string `form:"password" xorm:"varchar(60) not null"`
18 | FullName string `form:"fullName" xorm:"varchar(20) null"`
19 | Gender int `form:"gender" xorm:"int(1) default 0"`
20 | Qq string `form:"qq" xorm:"varchar(16) default null"`
21 | Tel string `form:"tel" xorm:"varchar(20) null"`
22 | Postcode string `form:"postcode" xorm:"varchar(10) default null"`
23 | Address string `form:"address" xorm:"varchar(80) default null"`
24 | Email string `form:"email" xorm:"varchar(45) unique"`
25 | Role Role `json:"role_id" xorm:"role_id int(3) default 1"`
26 | Dept Dept `json:"dept_id" xorm:"dept_id int(3) default 1"`
27 | Active bool `xorm:"tinyint(1) default 0"`
28 | Locked bool `xorm:"tinyint(1) default 0"`
29 | FailTime int `xorm:"int(1) default 0"`
30 | CreateUser string `xorm:"varchar(20) default 'SYSTEM'"`
31 | CreateDate time.Time `xorm:"datetime created"`
32 | UpdateUser string `xorm:"varchar(20) default 'SYSTEM'"`
33 | UpdateDate time.Time `xorm:"datetime updated"`
34 | Version int `form:"version" xorm:"int(11) version"`
35 | Page `xorm:"-"`
36 | }
37 |
38 | func (self *User) ShowName() string {
39 | if self.FullName != "" {
40 | return self.FullName
41 | }
42 | return self.Username
43 | }
44 |
45 | func (self *User) Exist() (bool, error) {
46 | return orm.Get(self)
47 | }
48 |
49 | func (self *User) ExistUsername() (bool, error) {
50 | return orm.Get(&User{Username: self.Username})
51 | }
52 |
53 | func (self *User) ExistEmail() (bool, error) {
54 | return orm.Get(&User{Email: self.Email})
55 | }
56 |
57 | func (self *User) GetUser() (*User, error) {
58 | user := &User{}
59 | _, err := orm.Id(self.Id).Get(user)
60 | return user, err
61 | }
62 |
63 | func (self *User) GetUserById(id int) (*User, error) {
64 | user := &User{Id: id}
65 | _, err := orm.Get(user)
66 | return user, err
67 | }
68 |
69 | func (self *User) Insert() error {
70 | self.FullName = self.Username
71 | self.Dept = Dept{Id: 1}
72 | self.Role = Role{Id: 4}
73 | self.Active = true
74 | self.CreateUser = "SYSTEM"
75 | self.UpdateUser = "SYSTEM"
76 | _, err := orm.InsertOne(self)
77 | Log.Info(self.Username, " inserted")
78 | return err
79 | }
80 |
81 | func (self *User) Update() error {
82 | self.Role = Role{}
83 | self.Dept = Dept{}
84 | _, err := orm.Id(self.Id).MustCols("gender").Update(self)
85 | Log.Info("User ", self.Username, " updated")
86 | return err
87 | }
88 |
89 | func (self *User) Delete() error {
90 | _, err := orm.Delete(self)
91 | Log.Info("User ", self.Username, " deleted")
92 | return err
93 | }
94 |
95 | func (self *User) DeleteUsers(array []int) error {
96 | _, err := orm.In("id", array).Delete(&User{})
97 | sql := "delete from `user` where id in ("
98 | for index, val := range array {
99 | sql += strconv.Itoa(val)
100 | if index < len(array)-1 {
101 | sql += ","
102 | }
103 | }
104 | sql += ")"
105 | _, err = orm.Exec(sql)
106 | Log.Info("Users: ", array, " deleted")
107 | return err
108 | }
109 |
110 | func (self *User) SetRole() error {
111 | var err error
112 | _, err = orm.Id(self.Id).MustCols("role_id").Update(&User{Role: self.Role, Version: self.Version})
113 | Log.Info("User ", self.Username, " roleId set to ", self.Role.Id)
114 | return err
115 | }
116 |
117 | func (self *User) SetLock(lock bool) error {
118 | var err error
119 | self, err = self.GetUser()
120 | _, err = orm.Id(self.Id).UseBool("locked").Update(&User{Locked: lock, Version: self.Version})
121 | if lock {
122 | Log.Info("User ", self.Username, " locked")
123 | } else {
124 | Log.Info("User ", self.Username, " unlocked")
125 | }
126 | return err
127 | }
128 |
129 | func (self *User) SelectAll() ([]User, error) {
130 | var users []User
131 | err := orm.Find(&users)
132 | return users, err
133 | }
134 |
135 | func (self *User) SearchByPage() ([]User, int64, error) {
136 | total, err := orm.Count(self)
137 | var users []User
138 | err = orm.OrderBy(self.GetSortProperties()[0].Column+" "+self.GetSortProperties()[0].Direction).Limit(self.GetPageSize(), self.GetDisplayStart()).Find(&users, self)
139 | return users, total, err
140 | }
141 |
142 | type UserLoginForm struct {
143 | Username string `form:"username" binding:"required"`
144 | Password string `form:"password" binding:"required"`
145 | }
146 |
147 | type UserRegisterForm struct {
148 | Username string `form:"username" binding:"required"`
149 | Password string `form:"password" binding:"required"`
150 | Email string `form:"email" binding:"required"`
151 | }
152 |
153 | type Password struct {
154 | Id int `form:"id" binding:"required"`
155 | CurrentPassword string `form:"currentPassword" binding:"required"`
156 | ConfirmPassword string `form:"confirmPassword" binding:"required"`
157 | }
158 |
159 | func (user UserRegisterForm) Validate(errors *binding.Errors, r *http.Request) {
160 | if len(user.Username) < 5 {
161 | errors.Fields["username"] = "Length of username should be longer than 5."
162 | }
163 | if len(user.Password) < 5 {
164 | errors.Fields["password"] = "Length of password should be longer than 5."
165 | }
166 | re := regexp.MustCompile(".+@.+\\..+")
167 | matched := re.Match([]byte(user.Email))
168 | if matched == false {
169 | errors.Fields["email"] = "Please enter a valid email address."
170 | }
171 | }
172 |
173 | func (password Password) Validate(errors *binding.Errors, r *http.Request) {
174 | if len(password.ConfirmPassword) < 5 {
175 | errors.Fields["confirmPassword"] = "Length of password should be longer than 5."
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/public/css/dataTables.bootstrap.css:
--------------------------------------------------------------------------------
1 | div.dataTables_length label {
2 | float: left;
3 | text-align: left;
4 | font-weight: normal;
5 | }
6 |
7 | div.dataTables_length select {
8 | width: 75px;
9 | }
10 |
11 | div.dataTables_filter label {
12 | float: right;
13 | font-weight: normal;
14 | }
15 |
16 | div.dataTables_filter input {
17 | width: 16em;
18 | }
19 |
20 | div.dataTables_info {
21 | padding-top: 8px;
22 | }
23 |
24 | div.dataTables_paginate {
25 | float: right;
26 | margin: 0;
27 | }
28 |
29 | div.dataTables_paginate ul.pagination {
30 | margin: 2px 0;
31 | white-space: nowrap;
32 | }
33 |
34 | table.dataTable,
35 | table.dataTable td,
36 | table.dataTable th {
37 | -webkit-box-sizing: content-box;
38 | -moz-box-sizing: content-box;
39 | box-sizing: content-box;
40 | }
41 |
42 | table.dataTable {
43 | clear: both;
44 | margin-top: 6px !important;
45 | margin-bottom: 6px !important;
46 | max-width: none !important;
47 | }
48 |
49 | table.dataTable thead .sorting,
50 | table.dataTable thead .sorting_asc,
51 | table.dataTable thead .sorting_desc,
52 | table.dataTable thead .sorting_asc_disabled,
53 | table.dataTable thead .sorting_desc_disabled {
54 | cursor: pointer;
55 | }
56 |
57 | table.dataTable thead .sorting {
58 | background: url('../images/sort_both.png') no-repeat center right;
59 | }
60 |
61 | table.dataTable thead .sorting_asc {
62 | background: url('../images/sort_asc.png') no-repeat center right;
63 | }
64 |
65 | table.dataTable thead .sorting_desc {
66 | background: url('../images/sort_desc.png') no-repeat center right;
67 | }
68 |
69 | table.dataTable thead .sorting_asc_disabled {
70 | background: url('../images/sort_asc_disabled.png') no-repeat center right;
71 | }
72 |
73 | table.dataTable thead .sorting_desc_disabled {
74 | background: url('../images/sort_desc_disabled.png') no-repeat center right;
75 | }
76 |
77 | table.dataTable th:active {
78 | outline: none;
79 | }
80 |
81 | /* Scrolling */
82 |
83 | div.dataTables_scrollHead table {
84 | margin-bottom: 0 !important;
85 | border-bottom-left-radius: 0;
86 | border-bottom-right-radius: 0;
87 | }
88 |
89 | div.dataTables_scrollHead table thead tr:last-child th:first-child,
90 | div.dataTables_scrollHead table thead tr:last-child td:first-child {
91 | border-bottom-left-radius: 0 !important;
92 | border-bottom-right-radius: 0 !important;
93 | }
94 |
95 | div.dataTables_scrollBody table {
96 | margin-top: 0 !important;
97 | margin-bottom: 0 !important;
98 | border-top: none;
99 | }
100 |
101 | div.dataTables_scrollBody tbody tr:first-child th,
102 | div.dataTables_scrollBody tbody tr:first-child td {
103 | border-top: none;
104 | }
105 |
106 | div.dataTables_scrollFoot table {
107 | margin-top: 0 !important;
108 | border-top: none;
109 | }
110 |
111 | /*
112 | * TableTools styles
113 | */
114 |
115 | .table tbody tr.active td,
116 | .table tbody tr.active th {
117 | color: white;
118 | background-color: #08C;
119 | }
120 |
121 | .table tbody tr.active:hover td,
122 | .table tbody tr.active:hover th {
123 | background-color: #0075b0 !important;
124 | }
125 |
126 | .table tbody tr.active a {
127 | color: white;
128 | }
129 |
130 | .table-striped tbody tr.active:nth-child(odd) td,
131 | .table-striped tbody tr.active:nth-child(odd) th {
132 | background-color: #017ebc;
133 | }
134 |
135 | table.DTTT_selectable tbody tr {
136 | cursor: pointer;
137 | }
138 |
139 | div.DTTT .btn {
140 | font-size: 12px;
141 | color: #333 !important;
142 | }
143 |
144 | div.DTTT .btn:hover {
145 | text-decoration: none !important;
146 | }
147 |
148 | ul.DTTT_dropdown.dropdown-menu {
149 | z-index: 2003;
150 | }
151 |
152 | ul.DTTT_dropdown.dropdown-menu a {
153 | color: #333 !important; /* needed only when demo_page.css is included */
154 | }
155 |
156 | ul.DTTT_dropdown.dropdown-menu li {
157 | position: relative;
158 | }
159 |
160 | ul.DTTT_dropdown.dropdown-menu li:hover a {
161 | color: white !important;
162 | background-color: #0088cc;
163 | }
164 |
165 | div.DTTT_collection_background {
166 | z-index: 2002;
167 | }
168 |
169 | /* TableTools information display */
170 |
171 | div.DTTT_print_info.modal {
172 | height: 150px;
173 | margin-top: -75px;
174 | text-align: center;
175 | }
176 |
177 | div.DTTT_print_info h6 {
178 | margin: 1em;
179 | font-size: 28px;
180 | font-weight: normal;
181 | line-height: 28px;
182 | }
183 |
184 | div.DTTT_print_info p {
185 | font-size: 14px;
186 | line-height: 20px;
187 | }
188 |
189 | /*
190 | * FixedColumns styles
191 | */
192 |
193 | div.DTFC_LeftHeadWrapper table,
194 | div.DTFC_LeftFootWrapper table,
195 | div.DTFC_RightHeadWrapper table,
196 | div.DTFC_RightFootWrapper table,
197 | table.DTFC_Cloned tr.even {
198 | background-color: white;
199 | }
200 |
201 | div.DTFC_RightHeadWrapper table,
202 | div.DTFC_LeftHeadWrapper table {
203 | margin-bottom: 0 !important;
204 | border-top-right-radius: 0 !important;
205 | border-bottom-left-radius: 0 !important;
206 | border-bottom-right-radius: 0 !important;
207 | }
208 |
209 | div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
210 | div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
211 | div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
212 | div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
213 | border-bottom-left-radius: 0 !important;
214 | border-bottom-right-radius: 0 !important;
215 | }
216 |
217 | div.DTFC_RightBodyWrapper table,
218 | div.DTFC_LeftBodyWrapper table {
219 | margin-bottom: 0 !important;
220 | border-top: none;
221 | }
222 |
223 | div.DTFC_RightBodyWrapper tbody tr:first-child th,
224 | div.DTFC_RightBodyWrapper tbody tr:first-child td,
225 | div.DTFC_LeftBodyWrapper tbody tr:first-child th,
226 | div.DTFC_LeftBodyWrapper tbody tr:first-child td {
227 | border-top: none;
228 | }
229 |
230 | div.DTFC_RightFootWrapper table,
231 | div.DTFC_LeftFootWrapper table {
232 | border-top: none;
233 | }
--------------------------------------------------------------------------------
/public/js/easykoo.js:
--------------------------------------------------------------------------------
1 | String.prototype.endWith = function (s) {
2 | if (s == null || s == "" || this.length == 0 || s.length > this.length)
3 | return false;
4 | if (this.substring(this.length - s.length) == s)
5 | return true;
6 | else
7 | return false;
8 | return true;
9 | };
10 |
11 | var formatTime = function (timeString) {
12 | var date = timeString.substr(0, 10)
13 | var time = timeString.substr(11, 8)
14 | return date + " " + time;
15 | };
16 |
17 | var changeLanguage = function (lang) {
18 | $.ajax('/language/change/' + lang, {
19 | dataType: 'json',
20 | type: "GET",
21 | success: function (data) {
22 | if (data.success) {
23 | location.reload();
24 | }
25 | }
26 | });
27 | }
28 |
29 | var filterSqlStr = function (value) {
30 | var sqlStr = sql_str().split(',');
31 | var flag = false;
32 |
33 | for (var i = 0; i < sqlStr.length; i++) {
34 | if (value.toLowerCase().indexOf(sqlStr[i]) != -1) {
35 | flag = true;
36 | break;
37 | }
38 | }
39 | return flag;
40 | }
41 |
42 | var sql_str = function () {
43 | var str = "and,delete,or,exec,insert,select,union,update,count,*,',join,>,<";
44 | return str;
45 | }
46 |
47 | var cutoff = function (content) {
48 | var cutoffLine = "----------"
49 | var index = content.indexOf(cutoffLine);
50 | if (index > 0) {
51 | content = content.replace(cutoffLine, "");
52 | var pre = content.substr(0, index);
53 | var preIndex = pre.lastIndexOf('');
54 | if (preIndex > 0) {
55 | preIndex += 4;
56 | } else {
57 | preIndex = pre.lastIndexOf('');
58 | if (preIndex > 0) {
59 | preIndex += 4;
60 | } else {
61 | return content;
62 | }
63 | }
64 | var pre = content.substr(0, preIndex);
65 | var nex = content.substr(preIndex, content.length);
66 | return pre + cutoffLine + nex;
67 | }
68 | return content;
69 | }
70 |
71 | var direct = function () {
72 | var winHeight = $(window).height()
73 |
74 | var $top = $('#goTop');
75 | var $bottom = $('#goBottom');
76 | var side = $('#side').offset().left;
77 | var width = $('#side').width();
78 | var pos = side + width + 25;
79 | $top.css({
80 | "left": pos + "px",
81 | "top": winHeight / 2 - 23 + "px",
82 | "width": "45px",
83 | "height": "45px",
84 | "position": "fixed",
85 | "opacity": .4
86 | })
87 | $bottom.css({
88 | "left": pos + "px",
89 | "top": winHeight / 2 + 23 + "px",
90 | "width": "45px",
91 | "height": "45px",
92 | "position": "fixed",
93 | "opacity": .4
94 | })
95 | $(window).scroll(function () {
96 | var scroll = $(this).scrollTop()
97 | if (scroll > 0) {
98 | $top.removeClass("hidden");
99 | } else {
100 | $top.addClass('hidden');
101 | }
102 |
103 | if (scroll + winHeight == $(document).height()) {
104 | $bottom.addClass('hidden');
105 | } else {
106 | $bottom.removeClass("hidden");
107 | }
108 | });
109 | $top.on("click", function () {
110 | $('html, body').animate({scrollTop: 0}, 300);
111 | return false;
112 | })
113 | $bottom.click(function () {
114 | $('html, body').animate({scrollTop: $(document).height()}, 300);
115 | return false;
116 | });
117 | }
118 |
119 | var setupPage = function (section, pageNo, totalPage) {
120 | var html = "";
121 | if (totalPage > 1) {
122 | html += '';
157 | section.html(html);
158 | }
159 | }
160 |
161 | var initTag = function () {
162 | $(".tag").hover(function () {
163 | $(this).find(".badge").removeClass("hidden");
164 | $(this).parent().css("padding-right", "8px");
165 | }, function () {
166 | $(this).find(".badge").addClass("hidden");
167 | $(this).parent().css("padding-right", "15px");
168 | })
169 | }
--------------------------------------------------------------------------------
/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/easykoo/binding"
5 | "github.com/easykoo/sessions"
6 | "github.com/go-martini/martini"
7 | "github.com/martini-contrib/render"
8 | "github.com/russross/blackfriday"
9 |
10 | . "github.com/easykoo/go-blog/auth"
11 | . "github.com/easykoo/go-blog/common"
12 | "github.com/easykoo/go-blog/handler"
13 | "github.com/easykoo/go-blog/middleware"
14 | "github.com/easykoo/go-blog/model"
15 |
16 | "encoding/gob"
17 | "html/template"
18 | "os"
19 | "time"
20 | )
21 |
22 | func init() {
23 | SetConfig()
24 | SetLog()
25 | gob.Register(model.User{})
26 | gob.Register(model.Settings{})
27 | Log.Debug("server initializing...")
28 | }
29 |
30 | func newMartini() *martini.ClassicMartini {
31 | r := martini.NewRouter()
32 | m := martini.New()
33 | m.Use(middleware.GetLogger())
34 | m.Map(model.SetEngine())
35 | m.Use(martini.Recovery())
36 | m.Use(martini.Static("public"))
37 | m.MapTo(r, (*martini.Routes)(nil))
38 | m.Action(r.Handle)
39 |
40 | m.Use(sessions.Sessions("my_session", middleware.NewDbStore(7*24*60*60)))
41 |
42 | m.Use(render.Renderer(render.Options{
43 | Directory: "templates",
44 | Extensions: []string{".tmpl", ".html"},
45 | Charset: "UTF-8",
46 | Funcs: []template.FuncMap{
47 | {
48 | "formatTime": func(args ...interface{}) string {
49 | return args[0].(time.Time).Format("Jan _2 15:04")
50 | },
51 | "cnFormatTime": func(args ...interface{}) string {
52 | return args[0].(time.Time).Format("2006-01-02 15:04")
53 | },
54 | "mdToHtml": func(args ...interface{}) template.HTML {
55 | return template.HTML(string(blackfriday.MarkdownBasic([]byte(args[0].(string)))))
56 | },
57 | "unescaped": func(args ...interface{}) template.HTML {
58 | return template.HTML(args[0].(string))
59 | },
60 | "equal": func(args ...interface{}) bool {
61 | return args[0] == args[1]
62 | },
63 | "tsl": func(lang string, format string) string {
64 | return Translate(lang, format)
65 | },
66 | "tslf": func(lang string, format string, args ...interface{}) string {
67 | return Translatef(lang, format, args...)
68 | },
69 | "privilege": func(user interface{}, module int) bool {
70 | if user == nil {
71 | return false
72 | }
73 | return CheckPermission(user, module)
74 | },
75 | "plus": func(args ...int) int {
76 | var result int
77 | for _, val := range args {
78 | result += val
79 | }
80 | return result
81 | },
82 | },
83 | },
84 | }))
85 |
86 | m.Use(middleware.InitContext())
87 | m.Use(middleware.RecordVisit())
88 |
89 | return &martini.ClassicMartini{m, r}
90 | }
91 |
92 | func main() {
93 | m := newMartini()
94 |
95 | m.Get("/", handler.Blog)
96 | m.Get("/index", handler.Blog)
97 | m.Get("/about", handler.About)
98 | m.Any("/contact", binding.Form(model.Feedback{}), handler.ContactHandler)
99 | m.Get("/language/change/:lang", handler.LangHandler)
100 |
101 | m.Group("/user", func(r martini.Router) {
102 | r.Any("/all", AuthRequest(Module_Account), handler.AllUserHandler)
103 | r.Any("/logout", handler.LogoutHandler)
104 | r.Any("/login", binding.Form(model.UserLoginForm{}), handler.LoginHandler)
105 | r.Any("/register", binding.Form(model.UserRegisterForm{}), handler.RegisterHandler)
106 | r.Any("/delete", AuthRequest(Module_Account), handler.DeleteUsers)
107 | r.Any("/delete/:id", AuthRequest(Module_Account), handler.DeleteUser)
108 | r.Any("/role", AuthRequest(Module_Account), handler.SetRole)
109 | r.Any("/ban/:id", AuthRequest(Module_Account), handler.BanUser)
110 | r.Any("/lift/:id", AuthRequest(Module_Account), handler.LiftUser)
111 | })
112 |
113 | m.Group("/profile", func(r martini.Router) {
114 | r.Any("/profile", AuthRequest(SignInRequired), binding.Form(model.User{}), handler.ProfileHandler)
115 | r.Any("/preferences", AuthRequest(SignInRequired), handler.PreferencesHandler)
116 | r.Any("/password", AuthRequest(SignInRequired), binding.Form(model.Password{}), handler.PasswordHandler)
117 | r.Any("/checkEmail", AuthRequest(SignInRequired), binding.Form(model.User{}), handler.CheckEmail)
118 | })
119 |
120 | m.Group("/admin", func(r martini.Router) {
121 | r.Get("/dashboard", AuthRequest(SignInRequired), handler.DashboardHandler)
122 | r.Any("/settings", AuthRequest(Module_Admin), binding.Form(model.Settings{}), handler.SettingsHandler)
123 | r.Post("/about", AuthRequest(Module_Admin), handler.AboutHandler)
124 | })
125 |
126 | m.Group("/feedback", func(r martini.Router) {
127 | r.Any("/all", AuthRequest(Module_Feedback), handler.AllFeedback)
128 | r.Any("/info", AuthRequest(Module_Feedback), handler.FeedbackInfo)
129 | r.Any("/delete", AuthRequest(Module_Feedback), handler.DeleteFeedbackArray)
130 | r.Any("/delete/:id", AuthRequest(Module_Feedback), handler.DeleteFeedback)
131 | r.Any("/view/:id", AuthRequest(Module_Feedback), handler.ViewFeedback)
132 | })
133 |
134 | m.Group("/link", func(r martini.Router) {
135 | r.Any("/all", AuthRequest(Module_Link), handler.AllLink)
136 | r.Any("/insert", AuthRequest(Module_Link), binding.Form(model.Link{}), handler.InsertLink)
137 | r.Any("/delete", AuthRequest(Module_Link), handler.DeleteLinkArray)
138 | r.Any("/delete/:id", AuthRequest(Module_Link), handler.DeleteLink)
139 | r.Any("/edit/:id", AuthRequest(Module_Link), handler.EditLink)
140 | })
141 |
142 | m.Group("/blog", func(r martini.Router) {
143 | r.Any("", handler.Blog)
144 | r.Any("/tag/:tag", handler.BlogWithTag)
145 | r.Any("/view/:id", handler.ViewBlog)
146 | r.Any("/all", AuthRequest(Module_Blog), handler.AllBlog)
147 | r.Any("/publish", AuthRequest(Module_Blog), binding.Form(model.Blog{}), handler.PublishBlog)
148 | r.Any("/save", AuthRequest(Module_Blog), binding.Form(model.Blog{}), handler.SaveBlog)
149 | r.Any("/edit/:id", AuthRequest(Module_Blog), handler.EditBlog)
150 | r.Any("/delete", AuthRequest(Module_Blog), handler.DeleteBlogArray)
151 | r.Any("/delete/:id", AuthRequest(Module_Blog), handler.DeleteBlog)
152 | r.Any("/forbid/:id", AuthRequest(Module_Blog), handler.ForbidBlog)
153 | r.Any("/permit/:id", AuthRequest(Module_Blog), handler.PermitBlog)
154 | })
155 |
156 | m.Group("/blog/comment", func(r martini.Router) {
157 | r.Any("", handler.Comment)
158 | r.Any("/delete/:blogId/:seq", AuthRequest(Module_Blog), handler.DeleteComment)
159 | })
160 |
161 | Log.Info("server is started...")
162 | os.Setenv("PORT", Cfg.MustValue("", "http_port", "3000"))
163 | m.Run()
164 | }
165 |
--------------------------------------------------------------------------------
/templates/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.contact.us"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 | {{template "layout/front_nav" .}}
27 |
28 |
29 |
30 |
32 |
42 |
52 |
62 |
69 |
70 |
71 |
72 |
73 |
74 | {{template "layout/footer" .}}
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/public/css/admin.css:
--------------------------------------------------------------------------------
1 | /* Global Styles */
2 |
3 | /* ------------------------------- */
4 |
5 | body {
6 | background-color: #f8f8f8;
7 | font-family: Ubuntu, Consolas, "Microsoft YaHei", Verdana, Tahoma, Arial, sans-serif;
8 | font-size: 14px;
9 | word-wrap:break-word;
10 | }
11 |
12 | /* Wrappers */
13 |
14 | /* ------------------------------- */
15 |
16 | #wrapper {
17 | width: 100%;
18 | }
19 |
20 | #page-wrapper {
21 | padding: 0 15px;
22 | min-height: 568px;
23 | background-color: #fff;
24 | }
25 |
26 | @media (min-width: 768px) {
27 | #page-wrapper {
28 | position: inherit;
29 | margin: 0 0 0 250px;
30 | padding: 0 30px;
31 | min-height: 1300px;
32 | border-left: 1px solid #e7e7e7;
33 | }
34 | }
35 |
36 | .navbar-static-side ul li {
37 | border-bottom: 1px solid #e7e7e7;
38 | }
39 |
40 | /* Navigation */
41 |
42 | /* ------------------------------- */
43 |
44 | /* Top Right Navigation Dropdown Styles */
45 |
46 | .navbar-top-links li {
47 | display: inline-block;
48 | }
49 |
50 | .navbar-top-links li:last-child {
51 | margin-right: 15px;
52 | }
53 |
54 | .navbar-top-links li a {
55 | padding: 15px;
56 | min-height: 50px;
57 | }
58 |
59 | .navbar-top-links .dropdown-menu li {
60 | display: block;
61 | }
62 |
63 | .navbar-top-links .dropdown-menu li:last-child {
64 | margin-right: 0;
65 | }
66 |
67 | .navbar-top-links .dropdown-menu li a {
68 | padding: 3px 20px;
69 | min-height: 0;
70 | }
71 |
72 | .navbar-top-links .dropdown-menu li a div {
73 | white-space: normal;
74 | }
75 |
76 | .navbar-top-links .dropdown-messages,
77 | .navbar-top-links .dropdown-tasks,
78 | .navbar-top-links .dropdown-alerts {
79 | width: 310px;
80 | min-width: 0;
81 | }
82 |
83 | .navbar-top-links .dropdown-messages {
84 | right: 0;
85 | left: auto;
86 | }
87 |
88 | .navbar-top-links .dropdown-tasks {
89 | margin-left: -59px;
90 | }
91 |
92 | .navbar-top-links .dropdown-alerts {
93 | margin-left: -123px;
94 | }
95 |
96 | .navbar-top-links .dropdown-user {
97 | right: 0;
98 | left: auto;
99 | }
100 |
101 | /* Sidebar Menu Styles */
102 |
103 | .sidebar-search {
104 | padding: 15px;
105 | }
106 |
107 | .arrow {
108 | float: right;
109 | }
110 |
111 | .fa.arrow:before {
112 | content: "\f104";
113 | }
114 |
115 | .active > a > .fa.arrow:before {
116 | content: "\f107";
117 | }
118 |
119 | .nav-second-level li,
120 | .nav-third-level li {
121 | border-bottom: none !important;
122 | }
123 |
124 | .nav-second-level li a {
125 | padding-left: 37px;
126 | }
127 |
128 | .nav-third-level li a {
129 | padding-left: 52px;
130 | }
131 |
132 | @media (min-width: 768px) {
133 | .navbar-static-side {
134 | z-index: 1;
135 | position: absolute;
136 | width: 250px;
137 | }
138 |
139 | .navbar-top-links .dropdown-messages,
140 | .navbar-top-links .dropdown-tasks,
141 | .navbar-top-links .dropdown-alerts {
142 | margin-left: auto;
143 | }
144 | }
145 |
146 | /* Buttons */
147 |
148 | /* ------------------------------- */
149 |
150 | .btn-outline {
151 | color: inherit;
152 | background-color: transparent;
153 | transition: all .5s;
154 | }
155 |
156 | .btn-primary.btn-outline {
157 | color: #428bca;
158 | }
159 |
160 | .btn-success.btn-outline {
161 | color: #5cb85c;
162 | }
163 |
164 | .btn-info.btn-outline {
165 | color: #5bc0de;
166 | }
167 |
168 | .btn-warning.btn-outline {
169 | color: #f0ad4e;
170 | }
171 |
172 | .btn-danger.btn-outline {
173 | color: #d9534f;
174 | }
175 |
176 | .btn-primary.btn-outline:hover,
177 | .btn-success.btn-outline:hover,
178 | .btn-info.btn-outline:hover,
179 | .btn-warning.btn-outline:hover,
180 | .btn-danger.btn-outline:hover {
181 | color: #fff;
182 | }
183 |
184 | /* Pages */
185 |
186 | /* ------------------------------- */
187 |
188 | /* Dashboard Chat */
189 |
190 | .chat {
191 | margin: 0;
192 | padding: 0;
193 | list-style: none;
194 | }
195 |
196 | .chat li {
197 | margin-bottom: 10px;
198 | padding-bottom: 5px;
199 | border-bottom: 1px dotted #B3A9A9;
200 | }
201 |
202 | .chat li.left .chat-body {
203 | margin-left: 60px;
204 | }
205 |
206 | .chat li.right .chat-body {
207 | margin-right: 60px;
208 | }
209 |
210 | .chat li .chat-body p {
211 | margin: 0;
212 | color: #777777;
213 | }
214 |
215 | .panel .slidedown .glyphicon,
216 | .chat .glyphicon {
217 | margin-right: 5px;
218 | }
219 |
220 | .chat-panel .panel-body {
221 | height: 350px;
222 | overflow-y: scroll;
223 | }
224 |
225 | /* Login Page */
226 |
227 | .login-panel {
228 | margin-top: 25%;
229 | }
230 |
231 | /* Flot Chart Containers */
232 |
233 | .flot-chart {
234 | display: block;
235 | height: 400px;
236 | }
237 |
238 | .flot-chart-content {
239 | width: 100%;
240 | height: 100%;
241 | }
242 |
243 | /* DataTables Overrides */
244 |
245 | table.dataTable thead .sorting,
246 | table.dataTable thead .sorting_asc:after,
247 | table.dataTable thead .sorting_desc,
248 | table.dataTable thead .sorting_asc_disabled,
249 | table.dataTable thead .sorting_desc_disabled {
250 | background: transparent;
251 | }
252 |
253 | table.dataTable thead .sorting_asc:after {
254 | content: "\f0de";
255 | float: right;
256 | font-family: fontawesome;
257 | }
258 |
259 | table.dataTable thead .sorting_desc:after {
260 | content: "\f0dd";
261 | float: right;
262 | font-family: fontawesome;
263 | }
264 |
265 | table.dataTable thead .sorting:after {
266 | content: "\f0dc";
267 | float: right;
268 | font-family: fontawesome;
269 | color: rgba(50, 50, 50, .5);
270 | }
271 |
272 | /* Circle Buttons */
273 |
274 | .btn-circle {
275 | width: 30px;
276 | height: 30px;
277 | padding: 6px 0;
278 | border-radius: 15px;
279 | text-align: center;
280 | font-size: 12px;
281 | line-height: 1.428571429;
282 | }
283 |
284 | .btn-circle.btn-lg {
285 | width: 50px;
286 | height: 50px;
287 | padding: 10px 16px;
288 | border-radius: 25px;
289 | font-size: 18px;
290 | line-height: 1.33;
291 | }
292 |
293 | .btn-circle.btn-xl {
294 | width: 70px;
295 | height: 70px;
296 | padding: 10px 16px;
297 | border-radius: 35px;
298 | font-size: 24px;
299 | line-height: 1.33;
300 | }
301 |
302 | .show-grid [class^="col-"] {
303 | padding-top: 10px;
304 | padding-bottom: 10px;
305 | border: 1px solid #ddd;
306 | background-color: #eee !important;
307 | }
308 |
309 | .show-grid {
310 | margin: 15px 0;
311 | }
312 |
313 | .tag {
314 | margin-top: 5px;
315 | cursor: pointer;
316 | }
317 |
318 | .page {
319 | text-align: center;
320 | }
--------------------------------------------------------------------------------
/dbscripts/baseSchema.sql:
--------------------------------------------------------------------------------
1 | DROP SCHEMA IF EXISTS easy_go;
2 | CREATE SCHEMA easy_go
3 | DEFAULT CHARACTER SET utf8
4 | COLLATE utf8_unicode_ci;
5 | USE easy_go;
6 |
7 | DROP TABLE IF EXISTS user;
8 | CREATE TABLE user (
9 | id INT(11) NOT NULL AUTO_INCREMENT,
10 | username VARCHAR(20) NOT NULL,
11 | password VARCHAR(60) NOT NULL,
12 | full_name VARCHAR(30) DEFAULT NULL,
13 | gender INT(1) DEFAULT '1',
14 | qq VARCHAR(16) DEFAULT NULL,
15 | tel VARCHAR(20) DEFAULT NULL,
16 | postcode VARCHAR(10) DEFAULT NULL,
17 | address VARCHAR(80) DEFAULT NULL,
18 | email VARCHAR(45) DEFAULT NULL,
19 | role_id INT(3) NOT NULL DEFAULT '3',
20 | dept_id INT(3) NOT NULL DEFAULT '1',
21 | active TINYINT(1) DEFAULT '0',
22 | locked TINYINT(1) DEFAULT '0',
23 | fail_time INT(2) DEFAULT '0',
24 | create_user VARCHAR(20) DEFAULT NULL,
25 | create_date DATETIME DEFAULT NULL,
26 | update_user VARCHAR(20) DEFAULT NULL,
27 | update_date DATETIME DEFAULT NULL,
28 | version INT(5) DEFAULT 1,
29 | PRIMARY KEY (id),
30 | UNIQUE KEY username_UNIQUE (username),
31 | UNIQUE KEY email_UNIQUE (email)
32 | );
33 |
34 | DROP TABLE IF EXISTS role;
35 | CREATE TABLE role (
36 | id INT(3) NOT NULL AUTO_INCREMENT,
37 | description VARCHAR(20) NOT NULL,
38 | create_user VARCHAR(20) DEFAULT NULL,
39 | create_date DATETIME DEFAULT NULL,
40 | update_user VARCHAR(20) DEFAULT NULL,
41 | update_date DATETIME DEFAULT NULL,
42 | version INT(5) DEFAULT 1,
43 | PRIMARY KEY (id)
44 | );
45 |
46 | DROP TABLE IF EXISTS dept;
47 | CREATE TABLE dept (
48 | id INT(3) NOT NULL AUTO_INCREMENT,
49 | description VARCHAR(20) NOT NULL,
50 | create_user VARCHAR(20) DEFAULT NULL,
51 | create_date DATETIME DEFAULT NULL,
52 | update_user VARCHAR(20) DEFAULT NULL,
53 | update_date DATETIME DEFAULT NULL,
54 | version INT(5) DEFAULT 1,
55 | PRIMARY KEY (id)
56 | );
57 |
58 | DROP TABLE IF EXISTS module;
59 | CREATE TABLE module (
60 | id INT(3) NOT NULL,
61 | description VARCHAR(40) NOT NULL,
62 | create_user VARCHAR(20) DEFAULT NULL,
63 | create_date DATETIME DEFAULT NULL,
64 | update_user VARCHAR(20) DEFAULT NULL,
65 | update_date DATETIME DEFAULT NULL,
66 | version INT(5) DEFAULT 1,
67 | PRIMARY KEY (id)
68 | );
69 |
70 | DROP TABLE IF EXISTS privilege;
71 | CREATE TABLE privilege (
72 | module_id INT(11) NOT NULL,
73 | role_id INT(11) NOT NULL,
74 | dept_id INT(11) NOT NULL,
75 | create_user VARCHAR(20) DEFAULT NULL,
76 | create_date DATETIME DEFAULT NULL,
77 | update_user VARCHAR(20) DEFAULT NULL,
78 | update_date DATETIME DEFAULT NULL,
79 | PRIMARY KEY (module_id, role_id, dept_id)
80 | );
81 |
82 | DROP TABLE IF EXISTS feedback;
83 | CREATE TABLE feedback (
84 | id INT(11) NOT NULL AUTO_INCREMENT,
85 | email VARCHAR(45) NOT NULL,
86 | name VARCHAR(20) NOT NULL,
87 | content VARCHAR(200) NOT NULL,
88 | viewed TINYINT(1) DEFAULT '0',
89 | create_date DATETIME DEFAULT NULL,
90 | view_date DATETIME DEFAULT NULL,
91 | PRIMARY KEY (id)
92 | );
93 |
94 | DROP TABLE IF EXISTS blog;
95 | CREATE TABLE blog (
96 | id INT(11) NOT NULL AUTO_INCREMENT,
97 | category_id INT(9) NOT NULL DEFAULT 1,
98 | title VARCHAR(60) NOT NULL,
99 | content BLOB NOT NULL,
100 | state VARCHAR(10) NOT NULL,
101 | priority INT(1) NULL DEFAULT 5,
102 | author_id INT(11) DEFAULT NULL,
103 | visit INT(9) DEFAULT 0,
104 | publish_date DATETIME DEFAULT NULL,
105 | forbid_comment TINYINT(1) DEFAULT 0,
106 | create_user VARCHAR(20) DEFAULT NULL,
107 | create_date DATETIME DEFAULT NULL,
108 | update_user VARCHAR(20) DEFAULT NULL,
109 | update_date DATETIME DEFAULT NULL,
110 | version INT(11) DEFAULT 1,
111 | PRIMARY KEY (id)
112 | );
113 |
114 | DROP TABLE IF EXISTS category;
115 | CREATE TABLE category (
116 | id INT(3) NOT NULL,
117 | description VARCHAR(40) NOT NULL,
118 | parent_id INT(3) NOT NULL,
119 | create_user VARCHAR(20) DEFAULT NULL,
120 | create_date DATETIME DEFAULT NULL,
121 | update_user VARCHAR(20) DEFAULT NULL,
122 | update_date DATETIME DEFAULT NULL,
123 | version INT(11) DEFAULT 1,
124 | PRIMARY KEY (id)
125 | );
126 |
127 | DROP TABLE IF EXISTS tag;
128 | CREATE TABLE tag (
129 | name VARCHAR(20) NOT NULL,
130 | blog_id INT(11) NOT NULL,
131 | PRIMARY KEY (name, blog_id)
132 | );
133 |
134 | DROP TABLE IF EXISTS settings;
135 | CREATE TABLE settings (
136 | id INT(1) NOT NULL DEFAULT 1,
137 | app_name VARCHAR(20) NOT NULL,
138 | owner_id INT(11) NOT NULL DEFAULT 1,
139 | about BLOB NULL,
140 | keywords VARCHAR(100) NULL,
141 | description VARCHAR(100) NULL,
142 | create_user VARCHAR(20) DEFAULT NULL,
143 | create_date DATETIME DEFAULT NULL,
144 | update_user VARCHAR(20) DEFAULT NULL,
145 | update_date DATETIME DEFAULT NULL,
146 | version INT(11) DEFAULT 1,
147 | PRIMARY KEY (id)
148 | );
149 |
150 | DROP TABLE IF EXISTS `comment`;
151 | CREATE TABLE `comment` (
152 | blog_id INT(11) NOT NULL,
153 | seq INT(5) NOT NULL,
154 | name VARCHAR(20) NULL,
155 | www VARCHAR(45) NULL,
156 | email VARCHAR(45) NULL,
157 | content VARCHAR(150) NOT NULL,
158 | parent_seq INT(3) NULL,
159 | ip VARCHAR(15) NOT NULL,
160 | create_user VARCHAR(20) DEFAULT NULL,
161 | create_date DATETIME DEFAULT NULL,
162 | update_user VARCHAR(20) DEFAULT NULL,
163 | update_date DATETIME DEFAULT NULL,
164 | version INT(11) DEFAULT 1,
165 | PRIMARY KEY (blog_id, seq)
166 | );
167 |
168 | DROP TABLE IF EXISTS visit;
169 | CREATE TABLE visit (
170 | session_id VARCHAR(60) NOT NULL,
171 | ip VARCHAR(15) NOT NULL,
172 | user_id INT(11) NULL,
173 | create_date DATETIME NOT NULL,
174 | PRIMARY KEY (session_id)
175 | );
176 |
177 | DROP TABLE IF EXISTS session_info;
178 | CREATE TABLE session_info (
179 | id VARCHAR(60) NOT NULL,
180 | content BLOB NOT NULL,
181 | age INT(9) NULL,
182 | create_date DATETIME NOT NULL,
183 | update_date DATETIME DEFAULT NULL,
184 | PRIMARY KEY (id)
185 | );
186 |
187 | DROP TABLE IF EXISTS link;
188 | CREATE TABLE link (
189 | id INT(11) NOT NULL AUTO_INCREMENT,
190 | description VARCHAR(40) NOT NULL,
191 | url VARCHAR(80) NOT NULL,
192 | create_user VARCHAR(20) DEFAULT NULL,
193 | create_date DATETIME DEFAULT NULL,
194 | update_user VARCHAR(20) DEFAULT NULL,
195 | update_date DATETIME DEFAULT NULL,
196 | version INT(11) DEFAULT 1,
197 | PRIMARY KEY (id)
198 | );
--------------------------------------------------------------------------------
/templates/profile/password.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.change.password"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {{template "layout/back_nav" .}}
30 | {{template "layout/left" .}}
31 |
32 |
33 |
39 | {{template "layout/message" .}}
40 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/templates/admin/dashboard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{tsl .Session.Lang "label.dashboard"}} - {{.Session.Settings.AppName}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
31 |
32 |
33 |
34 |
35 | {{$session := .Session}}
36 | {{template "layout/back_nav" .}}
37 | {{template "layout/left" .}}
38 |
39 |
45 |
46 |
47 |
48 |
49 | {{tsl .Session.Lang "label.statistics"}}
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | #
58 | {{tsl .Session.Lang "label.total.count"}}
59 | {{tsl .Session.Lang "label.month.count"}}
60 | {{tsl .Session.Lang "label.day.count"}}
61 |
62 |
63 |
64 |
65 | {{with .Response.Visit.GetStatistics}}
66 | #
67 | {{.TotalCount}}
68 | {{.MonthCount}}
69 | {{.DayCount}}
70 | {{end}}
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | {{tsl .Session.Lang "label.recent.visit"}}
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | #
97 | IP
98 | {{tsl .Session.Lang "label.user"}}
99 | {{tsl .Session.Lang "label.visit.time"}}
100 | {{tsl .Session.Lang "label.address"}}
101 |
102 |
103 |
104 | {{range .Response.Visit.Result}}
105 |
106 | #
107 | {{.Ip}}
108 | {{.User.FullName}}
109 | {{cnFormatTime .CreateDate}}
110 |
111 | {{if .Ip}}
112 |
114 |
116 | {{end}}
117 |
118 |
119 | {{end}}
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/templates/layout/left.html:
--------------------------------------------------------------------------------
1 |
2 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/handler/userHandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/easykoo/binding"
5 | "github.com/go-martini/martini"
6 |
7 | . "github.com/easykoo/go-blog/common"
8 | "github.com/easykoo/go-blog/middleware"
9 | "github.com/easykoo/go-blog/model"
10 |
11 | "encoding/json"
12 | )
13 |
14 | func LogoutHandler(ctx *middleware.Context) {
15 | ctx.S.Set("SignedUser", nil)
16 | ctx.Redirect("/index")
17 | }
18 |
19 | func LoginHandler(ctx *middleware.Context, formErr binding.Errors, loginUser model.UserLoginForm) {
20 | switch ctx.R.Method {
21 | case "POST":
22 | ctx.JoinFormErrors(formErr)
23 | password := Md5(loginUser.Password)
24 | user := &model.User{Username: loginUser.Username, Password: password}
25 | if !ctx.HasError() {
26 | if has, err := user.Exist(); has {
27 | PanicIf(err)
28 | if user.Locked {
29 | ctx.Set("User", user)
30 | ctx.AddError(Translate(ctx.S.Get("Lang").(string), "message.error.invalid.username.or.password"))
31 | ctx.HTML(200, "user/login", ctx)
32 | return
33 | }
34 | ctx.S.Set("SignedUser", user)
35 | Log.Info(user.Username, " login")
36 | ctx.Redirect("/admin/dashboard")
37 | } else {
38 | ctx.Set("User", user)
39 | ctx.AddError(Translate(ctx.S.Get("Lang").(string), "message.error.invalid.username.or.password"))
40 | ctx.HTML(200, "user/login", ctx)
41 | }
42 | } else {
43 | ctx.HTML(200, "user/login", ctx)
44 | }
45 | default:
46 | ctx.HTML(200, "user/login", ctx)
47 | }
48 | }
49 |
50 | func RegisterHandler(ctx *middleware.Context, formErr binding.Errors, user model.UserRegisterForm) {
51 | switch ctx.R.Method {
52 | case "POST":
53 | ctx.JoinFormErrors(formErr)
54 | if !ctx.HasError() {
55 | dbUser := model.User{Username: user.Username, Password: user.Password, Email: user.Email}
56 |
57 | if exist, err := dbUser.ExistUsername(); exist {
58 | PanicIf(err)
59 | ctx.AddFieldError("username", Translate(ctx.S.Get("Lang").(string), "message.error.already.exists"))
60 | }
61 |
62 | if exist, err := dbUser.ExistEmail(); exist {
63 | PanicIf(err)
64 | ctx.AddFieldError("email", Translate(ctx.S.Get("Lang").(string), "message.error.already.exists"))
65 | }
66 |
67 | if !ctx.HasError() {
68 | dbUser.Password = Md5(user.Password)
69 | err := dbUser.Insert()
70 | PanicIf(err)
71 | ctx.AddMessage(Translate(ctx.S.Get("Lang").(string), "message.register.success"))
72 | } else {
73 | ctx.Set("User", user)
74 | }
75 | ctx.HTML(200, "user/register", ctx)
76 | } else {
77 | ctx.Set("User", user)
78 | ctx.HTML(200, "user/register", ctx)
79 | }
80 | default:
81 | ctx.HTML(200, "user/register", ctx)
82 | }
83 | }
84 |
85 | func ProfileHandler(ctx *middleware.Context, formErr binding.Errors, user model.User) {
86 | switch ctx.R.Method {
87 | case "POST":
88 | ctx.JoinFormErrors(formErr)
89 | if !ctx.HasError() {
90 | err := user.Update()
91 | PanicIf(err)
92 | dbUser, err := user.GetUserById(user.Id)
93 | PanicIf(err)
94 | ctx.AddMessage(Translate(ctx.S.Get("Lang").(string), "message.change.success"))
95 | ctx.S.Set("SignedUser", dbUser)
96 | }
97 | ctx.HTML(200, "profile/profile", ctx)
98 | default:
99 | ctx.HTML(200, "profile/profile", ctx)
100 | }
101 | }
102 |
103 | func PasswordHandler(ctx *middleware.Context, formErr binding.Errors, password model.Password) {
104 | switch ctx.R.Method {
105 | case "POST":
106 | ctx.JoinFormErrors(formErr)
107 | if !ctx.HasError() {
108 | if password.CurrentPassword == password.ConfirmPassword {
109 | ctx.AddError(Translate(ctx.S.Get("Lang").(string), "message.error.password.not.changed"))
110 | } else {
111 | user := &model.User{Id: password.Id}
112 | dbUser, err := user.GetUserById(user.Id)
113 | PanicIf(err)
114 | if dbUser.Password == Md5(password.CurrentPassword) {
115 | dbUser.Password = Md5(password.ConfirmPassword)
116 | err := dbUser.Update()
117 | PanicIf(err)
118 | ctx.AddMessage(Translate(ctx.S.Get("Lang").(string), "message.change.success"))
119 | } else {
120 | ctx.AddError(Translate(ctx.S.Get("Lang").(string), "message.error.wrong.password"))
121 | }
122 | }
123 | }
124 | default:
125 | }
126 | ctx.HTML(200, "profile/password", ctx)
127 | }
128 |
129 | func CheckEmail(ctx *middleware.Context) {
130 | if user := ctx.S.Get("SignedUser"); user.(model.User).Email != ctx.R.Form["email"][0] {
131 | test := &model.User{Email: ctx.R.Form["email"][0]}
132 | if exist, _ := test.ExistEmail(); exist {
133 | ctx.JSON(200, Translate(ctx.S.Get("Lang").(string), "message.error.already.exists"))
134 | return
135 | }
136 | }
137 | ctx.JSON(200, true)
138 | }
139 |
140 | func AllUserHandler(ctx *middleware.Context) {
141 | switch ctx.R.Method {
142 | case "POST":
143 | user := new(model.User)
144 | user.SetPageActive(true)
145 | user.SetPageSize(ParseInt(ctx.R.FormValue("iDisplayLength")))
146 | user.SetDisplayStart(ParseInt(ctx.R.FormValue("iDisplayStart")))
147 | columnNum := ctx.R.FormValue("iSortCol_0")
148 | sortColumn := ctx.R.FormValue("mDataProp_" + columnNum)
149 | user.AddSortProperty(sortColumn, ctx.R.FormValue("sSortDir_0"))
150 | users, total, err := user.SearchByPage()
151 | PanicIf(err)
152 | ctx.Set("aaData", users)
153 | ctx.Set("iTotalDisplayRecords", total)
154 | ctx.Set("iTotalRecords", total)
155 | ctx.JSON(200, ctx.Response)
156 | default:
157 | ctx.HTML(200, "user/allUser", ctx)
158 | }
159 | }
160 |
161 | func DeleteUser(ctx *middleware.Context, params martini.Params) {
162 | id := params["id"]
163 | user := new(model.User)
164 | user.Id = ParseInt(id)
165 | err := user.Delete()
166 | PanicIf(err)
167 | ctx.Set("success", true)
168 | ctx.JSON(200, ctx.Response)
169 | }
170 |
171 | func DeleteUsers(ctx *middleware.Context) {
172 | users := ctx.R.FormValue("Users")
173 | var res []int
174 | json.Unmarshal([]byte(users), &res)
175 | user := new(model.User)
176 | err := user.DeleteUsers(res)
177 | PanicIf(err)
178 | ctx.Set("success", true)
179 | ctx.JSON(200, ctx.Response)
180 | }
181 |
182 | func SetRole(ctx *middleware.Context) {
183 | id := ctx.R.PostFormValue("Id")
184 | roleId := ctx.R.PostFormValue("RoleId")
185 | version := ctx.R.PostFormValue("Version")
186 | user := new(model.User)
187 | user.Id = ParseInt(id)
188 | user.Role.Id = ParseInt(roleId)
189 | user.Version = ParseInt(version)
190 | err := user.SetRole()
191 | PanicIf(err)
192 | ctx.Set("success", true)
193 | Log.Info("User: ", user.Id, " roleId set to ", roleId)
194 | ctx.JSON(200, ctx.Response)
195 | }
196 |
197 | func BanUser(ctx *middleware.Context, params martini.Params) {
198 | id := params["id"]
199 | user := new(model.User)
200 | user.Id = ParseInt(id)
201 | err := user.SetLock(true)
202 | PanicIf(err)
203 | ctx.Set("success", true)
204 | ctx.JSON(200, ctx.Response)
205 | }
206 |
207 | func LiftUser(ctx *middleware.Context, params martini.Params) {
208 | id := params["id"]
209 | user := new(model.User)
210 | user.Id = ParseInt(id)
211 | err := user.SetLock(false)
212 | PanicIf(err)
213 | ctx.Set("success", true)
214 | ctx.JSON(200, ctx.Response)
215 | }
216 |
217 | func PreferencesHandler(ctx *middleware.Context) {
218 | ctx.HTML(200, "profile/preferences", ctx)
219 | }
220 |
--------------------------------------------------------------------------------