You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

repo_dashbord.go 26 kB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. package repo
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "github.com/360EntSecGroup-Skylar/excelize/v2"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/repository"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/setting"
  15. )
  16. const DEFAULT_PAGE_SIZE = 10
  17. const DATE_FORMAT = "2006-01-02"
  18. const EXCEL_DATE_FORMAT = "20060102"
  19. type ProjectsPeriodData struct {
  20. RecordBeginTime string `json:"recordBeginTime"`
  21. LastUpdatedTime string `json:"lastUpdatedTime"`
  22. PageSize int `json:"pageSize"`
  23. TotalPage int `json:"totalPage"`
  24. TotalCount int64 `json:"totalCount"`
  25. PageRecords []*models.RepoStatistic `json:"pageRecords"`
  26. }
  27. type UserInfo struct {
  28. User string `json:"user"`
  29. Mode int `json:"mode"`
  30. PR int64 `json:"pr"`
  31. Commit int `json:"commit"`
  32. RelAvatarLink string `json:"relAvatarLink"`
  33. Email string `json:"email"`
  34. }
  35. type ProjectLatestData struct {
  36. RecordBeginTime string `json:"recordBeginTime"`
  37. LastUpdatedTime string `json:"lastUpdatedTime"`
  38. CreatTime string `json:"creatTime"`
  39. OpenI float64 `json:"openi"`
  40. Comment int64 `json:"comment"`
  41. View int64 `json:"view"`
  42. Download int64 `json:"download"`
  43. IssueClosedRatio float32 `json:"issueClosedRatio"`
  44. Impact float64 `json:"impact"`
  45. Completeness float64 `json:"completeness"`
  46. Liveness float64 `json:"liveness"`
  47. ProjectHealth float64 `json:"projectHealth"`
  48. TeamHealth float64 `json:"teamHealth"`
  49. Growth float64 `json:"growth"`
  50. Description string `json:"description"`
  51. Top10 []UserInfo `json:"top10"`
  52. }
  53. func RestoreForkNumber(ctx *context.Context) {
  54. repos, err := models.GetAllRepositories()
  55. if err != nil {
  56. log.Error("GetAllRepositories failed: %v", err.Error())
  57. return
  58. }
  59. for _, repo := range repos {
  60. models.RestoreRepoStatFork(int64(repo.NumForks), repo.ID)
  61. }
  62. ctx.JSON(http.StatusOK, struct{}{})
  63. }
  64. func GetAllProjectsPeriodStatistics(ctx *context.Context) {
  65. recordBeginTime, err := getRecordBeginTime()
  66. if err != nil {
  67. log.Error("Can not get record begin time", err)
  68. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  69. return
  70. }
  71. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  72. if err != nil {
  73. log.Error("Parameter is wrong", err)
  74. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
  75. return
  76. }
  77. q := ctx.QueryTrim("q")
  78. page := ctx.QueryInt("page")
  79. if page <= 0 {
  80. page = 1
  81. }
  82. pageSize := ctx.QueryInt("pagesize")
  83. if pageSize <= 0 {
  84. pageSize = DEFAULT_PAGE_SIZE
  85. }
  86. orderBy := getOrderBy(ctx)
  87. latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime()
  88. if err != nil {
  89. log.Error("Can not query the last updated time.", err)
  90. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  91. return
  92. }
  93. countSql := generateCountSql(beginTime, endTime, latestDate, q)
  94. total, err := models.CountRepoStatByRawSql(countSql)
  95. if err != nil {
  96. log.Error("Can not query total count.", err)
  97. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  98. return
  99. }
  100. sql := generateSqlByType(ctx, beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  101. projectsPeriodData := ProjectsPeriodData{
  102. RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
  103. PageSize: pageSize,
  104. TotalPage: getTotalPage(total, pageSize),
  105. TotalCount: total,
  106. LastUpdatedTime: latestUpdatedTime,
  107. PageRecords: models.GetRepoStatisticByRawSql(sql),
  108. }
  109. ctx.JSON(http.StatusOK, projectsPeriodData)
  110. }
  111. func generateSqlByType(ctx *context.Context, beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  112. sql := ""
  113. if ctx.QueryTrim("type") == "all" {
  114. sql = generateTypeAllSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  115. } else {
  116. sql = generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  117. }
  118. return sql
  119. }
  120. func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {
  121. recordBeginTime, err := getRecordBeginTime()
  122. if err != nil {
  123. log.Error("Can not get record begin time", err)
  124. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  125. return
  126. }
  127. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  128. if err != nil {
  129. log.Error("Parameter is wrong", err)
  130. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
  131. return
  132. }
  133. q := ctx.QueryTrim("q")
  134. page := ctx.QueryInt("page")
  135. if page <= 0 {
  136. page = 1
  137. }
  138. pageSize := 1000
  139. orderBy := getOrderBy(ctx)
  140. _, latestDate, err := models.GetRepoStatLastUpdatedTime()
  141. if err != nil {
  142. log.Error("Can not query the last updated time.", err)
  143. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  144. return
  145. }
  146. countSql := generateCountSql(beginTime, endTime, latestDate, q)
  147. total, err := models.CountRepoStatByRawSql(countSql)
  148. if err != nil {
  149. log.Error("Can not query total count.", err)
  150. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  151. return
  152. }
  153. var projectAnalysis = ctx.Tr("repo.repo_stat_inspect")
  154. fileName := getFileName(ctx, beginTime, endTime, projectAnalysis)
  155. totalPage := getTotalPage(total, pageSize)
  156. f := excelize.NewFile()
  157. index := f.NewSheet(projectAnalysis)
  158. f.DeleteSheet("Sheet1")
  159. for k, v := range allProjectsPeroidHeader(ctx) {
  160. f.SetCellValue(projectAnalysis, k, v)
  161. }
  162. var row = 2
  163. for i := 0; i <= totalPage; i++ {
  164. pageRecords := models.GetRepoStatisticByRawSql(generateSqlByType(ctx, beginTime, endTime, latestDate, q, orderBy, i+1, pageSize))
  165. for _, record := range pageRecords {
  166. for k, v := range allProjectsPeroidValues(row, record, ctx) {
  167. f.SetCellValue(projectAnalysis, k, v)
  168. }
  169. row++
  170. }
  171. }
  172. f.SetActiveSheet(index)
  173. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
  174. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  175. f.WriteTo(ctx.Resp)
  176. }
  177. func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) {
  178. page := ctx.QueryInt("page")
  179. if page <= 0 {
  180. page = 1
  181. }
  182. pageSize := 1000
  183. _, latestDate, err := models.GetRepoStatLastUpdatedTime()
  184. if err != nil {
  185. log.Error("Can not query the last updated time.", err)
  186. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  187. return
  188. }
  189. date := ctx.QueryTrim("date")
  190. if date == "" {
  191. date = latestDate
  192. }
  193. countSql := generateOpenICountSql(date)
  194. total, err := models.CountRepoStatByRawSql(countSql)
  195. if err != nil {
  196. log.Error("Can not query total count.", err)
  197. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  198. return
  199. }
  200. var projectAnalysis = ctx.Tr("repo.repo_stat_inspect")
  201. fileName := "项目分析_OPENI_" + date + ".xlsx"
  202. totalPage := getTotalPage(total, pageSize)
  203. f := excelize.NewFile()
  204. index := f.NewSheet(projectAnalysis)
  205. f.DeleteSheet("Sheet1")
  206. for k, v := range allProjectsOpenIHeader() {
  207. f.SetCellValue(projectAnalysis, k, v)
  208. }
  209. var row = 2
  210. for i := 0; i <= totalPage; i++ {
  211. pageRecords := models.GetRepoStatisticByRawSql(generateTypeAllOpenISql(date, i+1, pageSize))
  212. for _, record := range pageRecords {
  213. for k, v := range allProjectsOpenIValues(row, record, ctx) {
  214. f.SetCellValue(projectAnalysis, k, v)
  215. }
  216. row++
  217. }
  218. }
  219. f.SetActiveSheet(index)
  220. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
  221. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  222. f.WriteTo(ctx.Resp)
  223. }
  224. func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string {
  225. baseName := projectAnalysis + "_"
  226. if ctx.QueryTrim("q") != "" {
  227. baseName = baseName + ctx.QueryTrim("q") + "_"
  228. }
  229. if ctx.QueryTrim("type") == "all" {
  230. baseName = baseName + ctx.Tr("repo.all")
  231. } else {
  232. baseName = baseName + beginTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT)
  233. }
  234. frontName := baseName + ".xlsx"
  235. return frontName
  236. }
  237. func allProjectsPeroidHeader(ctx *context.Context) map[string]string {
  238. return map[string]string{"A1": ctx.Tr("admin.repos.id"), "B1": ctx.Tr("admin.repos.projectName"), "C1": ctx.Tr("repo.owner"), "D1": ctx.Tr("admin.repos.isPrivate"), "E1": ctx.Tr("admin.repos.openi"), "F1": ctx.Tr("admin.repos.visit"), "G1": ctx.Tr("admin.repos.download"), "H1": ctx.Tr("admin.repos.pr"), "I1": ctx.Tr("admin.repos.commit"),
  239. "J1": ctx.Tr("admin.repos.watches"), "K1": ctx.Tr("admin.repos.stars"), "L1": ctx.Tr("admin.repos.forks"), "M1": ctx.Tr("admin.repos.issues"), "N1": ctx.Tr("admin.repos.closedIssues"), "O1": ctx.Tr("admin.repos.contributor")}
  240. }
  241. func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string {
  242. return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.DisplayName(), getCellName("C", row): rs.OwnerName, getCellName("D", row): getIsPrivateDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
  243. getCellName("F", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("G", row): strconv.FormatInt(rs.NumDownloads, 10), getCellName("H", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("I", row): strconv.FormatInt(rs.NumCommits, 10),
  244. getCellName("J", row): strconv.FormatInt(rs.NumWatches, 10), getCellName("K", row): strconv.FormatInt(rs.NumStars, 10), getCellName("L", row): strconv.FormatInt(rs.NumForks, 10), getCellName("M", row): strconv.FormatInt(rs.NumIssues, 10),
  245. getCellName("N", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("O", row): strconv.FormatInt(rs.NumContributor, 10),
  246. }
  247. }
  248. func allProjectsOpenIHeader() map[string]string {
  249. return map[string]string{"A1": "ID", "B1": "项目名称", "C1": "拥有者", "D1": "是否私有", "E1": "OpenI指数",
  250. "F1": "影响力", "G1": "成熟度", "H1": "活跃度", "I1": "项目健康度", "J1": "团队健康度", "K1": "项目发展趋势",
  251. "L1": "关注数", "M1": "点赞数", "N1": "派生数", "O1": "代码下载量", "P1": "评论数", "Q1": "浏览量", "R1": "已解决任务数", "S1": "版本发布数量", "T1": "有效开发年龄",
  252. "U1": "数据集", "V1": "模型数", "W1": "百科页面数量", "X1": "提交数", "Y1": "任务数", "Z1": "PR数", "AA1": "版本发布数量", "AB1": "任务完成比例", "AC1": "贡献者数", "AD1": "关键贡献者数",
  253. "AE1": "新人增长量", "AF1": "代码规模增长量", "AG1": "任务增长量", "AH1": "新人增长量", "AI1": "提交增长量", "AJ1": "评论增长量",
  254. }
  255. }
  256. func allProjectsOpenIValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string {
  257. return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.DisplayName(), getCellName("C", row): rs.OwnerName, getCellName("D", row): getIsPrivateDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
  258. getCellName("F", row): strconv.FormatFloat(rs.Impact, 'f', 2, 64), getCellName("G", row): strconv.FormatFloat(rs.Completeness, 'f', 2, 64), getCellName("H", row): strconv.FormatFloat(rs.Liveness, 'f', 2, 64), getCellName("I", row): strconv.FormatFloat(rs.ProjectHealth, 'f', 2, 64), getCellName("J", row): strconv.FormatFloat(rs.TeamHealth, 'f', 2, 64), getCellName("K", row): strconv.FormatFloat(rs.Growth, 'f', 2, 64),
  259. getCellName("L", row): strconv.FormatInt(rs.NumWatches, 10), getCellName("M", row): strconv.FormatInt(rs.NumStars, 10), getCellName("N", row): strconv.FormatInt(rs.NumForks, 10), getCellName("O", row): strconv.FormatInt(rs.NumDownloads, 10),
  260. getCellName("P", row): strconv.FormatInt(rs.NumComments, 10), getCellName("Q", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("R", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("S", row): strconv.FormatInt(rs.NumVersions, 10),
  261. getCellName("T", row): strconv.FormatInt(rs.NumDevMonths, 10), getCellName("U", row): strconv.FormatInt(rs.DatasetSize, 10), getCellName("V", row): strconv.FormatInt(rs.NumModels, 10), getCellName("W", row): strconv.FormatInt(rs.NumWikiViews, 10),
  262. getCellName("X", row): strconv.FormatInt(rs.NumCommits, 10), getCellName("Y", row): strconv.FormatInt(rs.NumIssues, 10), getCellName("Z", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("AA", row): strconv.FormatInt(rs.NumVersions, 10),
  263. getCellName("AB", row): strconv.FormatFloat(float64(rs.IssueFixedRate), 'f', 2, 64), getCellName("AC", row): strconv.FormatInt(rs.NumContributor, 10), getCellName("AD", row): strconv.FormatInt(rs.NumKeyContributor, 10), getCellName("AE", row): strconv.FormatInt(rs.NumContributorsGrowth, 10),
  264. getCellName("AF", row): strconv.FormatInt(rs.NumCommitLinesGrowth, 10), getCellName("AG", row): strconv.FormatInt(rs.NumIssuesGrowth, 10), getCellName("AH", row): strconv.FormatInt(rs.NumContributorsGrowth, 10), getCellName("AI", row): strconv.FormatInt(rs.NumCommitsGrowth, 10), getCellName("AJ", row): strconv.FormatInt(rs.NumCommentsGrowth, 10),
  265. }
  266. }
  267. func getCellName(col string, row int) string {
  268. return col + strconv.Itoa(row)
  269. }
  270. func getIsPrivateDisplay(private bool, ctx *context.Context) string {
  271. if private {
  272. return ctx.Tr("admin.repos.yes")
  273. } else {
  274. return ctx.Tr("admin.repos.no")
  275. }
  276. }
  277. func GetProjectLatestStatistics(ctx *context.Context) {
  278. repoId := ctx.Params(":id")
  279. recordBeginTime, err := getRecordBeginTime()
  280. if err != nil {
  281. log.Error("Can not get record begin time", err)
  282. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  283. return
  284. }
  285. latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId)
  286. repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)
  287. repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt)
  288. if err != nil {
  289. log.Error("Can not get the repo statistics "+repoId, err)
  290. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error"))
  291. return
  292. }
  293. repository, err := models.GetRepositoryByID(repoIdInt)
  294. if err != nil {
  295. log.Error("Can not get the repo info "+repoId, err)
  296. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error"))
  297. return
  298. }
  299. projectLatestData := ProjectLatestData{
  300. RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
  301. CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT),
  302. LastUpdatedTime: latestUpdatedTime,
  303. OpenI: repoStat.RadarTotal,
  304. Comment: repoStat.NumComments,
  305. View: repoStat.NumVisits,
  306. Download: repoStat.NumDownloads,
  307. IssueClosedRatio: repoStat.IssueFixedRate,
  308. Impact: repoStat.Impact,
  309. Completeness: repoStat.Completeness,
  310. Liveness: repoStat.Liveness,
  311. ProjectHealth: repoStat.ProjectHealth,
  312. TeamHealth: repoStat.TeamHealth,
  313. Growth: repoStat.Growth,
  314. Description: repository.Description,
  315. }
  316. contributors, err := models.GetTop10Contributor(repository.RepoPath())
  317. if err != nil {
  318. log.Error("can not get contributors", err)
  319. }
  320. users := make([]UserInfo, 0)
  321. for _, contributor := range contributors {
  322. mode := repository.GetCollaboratorMode(contributor.UserId)
  323. if mode == -1 {
  324. if contributor.IsAdmin {
  325. mode = int(models.AccessModeAdmin)
  326. }
  327. if contributor.UserId == repository.OwnerID {
  328. mode = int(models.AccessModeOwner)
  329. }
  330. }
  331. pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId)
  332. userInfo := UserInfo{
  333. User: contributor.Committer,
  334. Commit: contributor.CommitCnt,
  335. Mode: mode,
  336. PR: pr,
  337. RelAvatarLink: contributor.RelAvatarLink,
  338. Email: contributor.Email,
  339. }
  340. users = append(users, userInfo)
  341. }
  342. projectLatestData.Top10 = users
  343. ctx.JSON(http.StatusOK, projectLatestData)
  344. }
  345. func GetProjectPeriodStatistics(ctx *context.Context) {
  346. repoId := ctx.Params(":id")
  347. recordBeginTime, err := getRecordBeginTime()
  348. if err != nil {
  349. log.Error("Can not get record begin time", err)
  350. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  351. return
  352. }
  353. repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)
  354. if err != nil {
  355. log.Error("Can not get record begin time", err)
  356. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  357. return
  358. }
  359. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  360. isOpenI := ctx.QueryBool("openi")
  361. var repositorys []*models.RepoStatistic
  362. if isOpenI {
  363. repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt))
  364. } else {
  365. repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt))
  366. }
  367. ctx.JSON(http.StatusOK, repositorys)
  368. }
  369. func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string {
  370. sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" +
  371. " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  372. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " order by created_unix"
  373. return sql
  374. }
  375. func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string {
  376. sql := "SELECT date, num_visits,num_downloads_added as num_downloads,num_commits_added as num_commits FROM repo_statistic" +
  377. " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  378. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " order by created_unix desc"
  379. return sql
  380. }
  381. func generateCountSql(beginTime time.Time, endTime time.Time, latestDate string, q string) string {
  382. countSql := "SELECT count(*) FROM " +
  383. "(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  384. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  385. "(SELECT repo_id,name,alias,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" +
  386. " where A.repo_id=B.repo_id"
  387. if q != "" {
  388. countSql = countSql + " and LOWER(B.alias) like '%" + strings.ToLower(q) + "%'"
  389. }
  390. return countSql
  391. }
  392. func generateOpenICountSql(latestDate string) string {
  393. countSql := "SELECT count(*) FROM " +
  394. "public.repo_statistic where date='" + latestDate + "'"
  395. return countSql
  396. }
  397. func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  398. sql := "SELECT A.repo_id,name,alias,owner_name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " +
  399. "(SELECT repo_id,sum(num_visits) as num_visits " +
  400. " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  401. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  402. "(SELECT repo_id,name,alias,owner_name,is_private,radar_total,num_watches,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor from public.repo_statistic where date='" + latestDate + "') B" +
  403. " where A.repo_id=B.repo_id"
  404. if q != "" {
  405. sql = sql + " and LOWER(alias) like '%" + strings.ToLower(q) + "%'"
  406. }
  407. sql = sql + " order by " + orderBy + " desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  408. return sql
  409. }
  410. func generateTypeAllOpenISql(latestDate string, page int, pageSize int) string {
  411. sql := "SELECT id, repo_id, date, num_watches, num_stars, num_forks, num_downloads, num_comments, num_visits, num_closed_issues, num_versions, num_dev_months, repo_size, dataset_size, num_models, num_wiki_views, num_commits, num_issues, num_pulls, issue_fixed_rate, num_contributor, num_key_contributor, num_contributors_growth, num_commits_growth, num_commit_lines_growth, num_issues_growth, num_comments_growth, impact, completeness, liveness, project_health, team_health, growth, radar_total, name,alias, is_private, owner_name FROM " +
  412. " public.repo_statistic where date='" + latestDate + "'"
  413. sql = sql + " order by radar_total desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  414. return sql
  415. }
  416. func generatePageSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  417. sql := "SELECT A.repo_id,name,alias,owner_name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " +
  418. "(SELECT repo_id,sum(num_watches_added) as num_watches,sum(num_visits) as num_visits, sum(num_downloads_added) as num_downloads,sum(num_pulls_added) as num_pulls,sum(num_commits_added) as num_commits,sum(num_stars_added) as num_stars,sum(num_forks_added) num_forks,sum(num_issues_added) as num_issues,sum(num_closed_issues_added) as num_closed_issues,sum(num_contributor_added) as num_contributor " +
  419. " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  420. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  421. "(SELECT repo_id,name,alias,owner_name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" +
  422. " where A.repo_id=B.repo_id"
  423. if q != "" {
  424. sql = sql + " and LOWER(B.alias) like '%" + strings.ToLower(q) + "%'"
  425. }
  426. sql = sql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  427. return sql
  428. }
  429. func getOrderBy(ctx *context.Context) string {
  430. orderBy := ""
  431. switch ctx.Query("sort") {
  432. case "openi":
  433. orderBy = "B.radar_total"
  434. case "view":
  435. orderBy = "A.num_visits"
  436. case "download":
  437. orderBy = "A.num_downloads"
  438. case "pr":
  439. orderBy = "A.num_pulls"
  440. case "commit":
  441. orderBy = "A.num_commits"
  442. case "watch":
  443. orderBy = "A.num_watches"
  444. case "star":
  445. orderBy = "A.num_stars"
  446. case "fork":
  447. orderBy = "A.num_forks"
  448. case "issue":
  449. orderBy = "A.num_issues"
  450. case "issue_closed":
  451. orderBy = "A.num_closed_issues"
  452. case "contributor":
  453. orderBy = "A.num_contributor"
  454. default:
  455. orderBy = "B.radar_total"
  456. }
  457. return orderBy
  458. }
  459. func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) {
  460. queryType := ctx.QueryTrim("type")
  461. now := time.Now()
  462. recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1)
  463. beginTimeStr := ctx.QueryTrim("beginTime")
  464. endTimeStr := ctx.QueryTrim("endTime")
  465. var beginTime time.Time
  466. var endTime time.Time
  467. var err error
  468. if queryType != "" {
  469. if queryType == "all" {
  470. beginTime = recordBeginTimeTemp
  471. endTime = now
  472. } else if queryType == "yesterday" {
  473. endTime = now
  474. beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
  475. } else if queryType == "current_week" {
  476. beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+2) //begin from monday
  477. beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
  478. endTime = now
  479. } else if queryType == "current_month" {
  480. endTime = now
  481. beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location())
  482. } else if queryType == "monthly" {
  483. endTime = now
  484. beginTime = now.AddDate(0, -1, 1)
  485. beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
  486. } else if queryType == "current_year" {
  487. endTime = now
  488. beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location())
  489. } else if queryType == "last_month" {
  490. lastMonthTime := now.AddDate(0, -1, 0)
  491. beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location())
  492. endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location())
  493. } else {
  494. return now, now, fmt.Errorf("The value of type parameter is wrong.")
  495. }
  496. } else {
  497. if beginTimeStr == "" || endTimeStr == "" {
  498. //如果查询类型和开始时间结束时间都未设置,按queryType=all处理
  499. beginTime = recordBeginTimeTemp
  500. endTime = now
  501. } else {
  502. beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
  503. if err != nil {
  504. return now, now, err
  505. }
  506. endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
  507. if err != nil {
  508. return now, now, err
  509. }
  510. beginTime = beginTime.AddDate(0, 0, 1)
  511. endTime = endTime.AddDate(0, 0, 1)
  512. }
  513. }
  514. if beginTime.Before(recordBeginTimeTemp) {
  515. beginTime = recordBeginTimeTemp
  516. }
  517. return beginTime, endTime, nil
  518. }
  519. func getRecordBeginTime() (time.Time, error) {
  520. return time.ParseInLocation(DATE_FORMAT, setting.RadarMap.RecordBeginTime, time.Local)
  521. }
  522. func getTotalPage(total int64, pageSize int) int {
  523. another := 0
  524. if int(total)%pageSize != 0 {
  525. another = 1
  526. }
  527. return int(total)/pageSize + another
  528. }
  529. func ProjectNumVisit(ctx *context.APIContext) {
  530. var (
  531. err error
  532. )
  533. var userName = ctx.Query("user")
  534. var projectName = ctx.Query("project")
  535. var beginTime = ctx.Query("begintime")
  536. var endTime = ctx.Query("endtime")
  537. var ProjectNumVisits int
  538. ProjectNumVisits, err = repository.AppointProjectView(userName, projectName, beginTime, endTime) //访问量
  539. if err != nil {
  540. ctx.NotFound(err)
  541. }
  542. log.Info("ProjectNumVisits is:", ProjectNumVisits)
  543. ctx.JSON(http.StatusOK, map[string]interface{}{
  544. "ProjectNumVisits": ProjectNumVisits,
  545. "StatusOK": 0,
  546. })
  547. }