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 37 kB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  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 MONTH_FORMAT = "2006-01"
  19. const EXCEL_DATE_FORMAT = "20060102"
  20. const CREATE_TIME_FORMAT = "2006/01/02 15:04:05"
  21. const UPDATE_TIME_FORMAT = "2006-01-02 15:04:05"
  22. type ProjectsPeriodData struct {
  23. RecordBeginTime string `json:"recordBeginTime"`
  24. LastUpdatedTime string `json:"lastUpdatedTime"`
  25. PageSize int `json:"pageSize"`
  26. TotalPage int `json:"totalPage"`
  27. TotalCount int64 `json:"totalCount"`
  28. PageRecords []*models.RepoStatistic `json:"pageRecords"`
  29. }
  30. type UserInfo struct {
  31. User string `json:"user"`
  32. Mode int `json:"mode"`
  33. PR int64 `json:"pr"`
  34. Commit int `json:"commit"`
  35. RelAvatarLink string `json:"relAvatarLink"`
  36. Email string `json:"email"`
  37. }
  38. type ProjectLatestData struct {
  39. RecordBeginTime string `json:"recordBeginTime"`
  40. LastUpdatedTime string `json:"lastUpdatedTime"`
  41. CreatTime string `json:"creatTime"`
  42. OpenI float64 `json:"openi"`
  43. Comment int64 `json:"comment"`
  44. View int64 `json:"view"`
  45. Download int64 `json:"download"`
  46. IssueClosedRatio float32 `json:"issueClosedRatio"`
  47. Impact float64 `json:"impact"`
  48. Completeness float64 `json:"completeness"`
  49. Liveness float64 `json:"liveness"`
  50. ProjectHealth float64 `json:"projectHealth"`
  51. TeamHealth float64 `json:"teamHealth"`
  52. Growth float64 `json:"growth"`
  53. Description string `json:"description"`
  54. Top10 []UserInfo `json:"top10"`
  55. }
  56. type ProjectSummaryBaseData struct {
  57. NumReposAdd int64 `json:"numReposAdd"`
  58. NumRepoPublicAdd int64 `json:"numRepoPublicAdd"`
  59. NumRepoPrivateAdd int64 `json:"numRepoPrivateAdd"`
  60. NumRepoForkAdd int64 `json:"numRepoForkAdd"`
  61. NumRepoMirrorAdd int64 `json:"numRepoMirrorAdd"`
  62. NumRepoSelfAdd int64 `json:"numRepoSelfAdd"`
  63. NumRepos int64 `json:"numRepos"`
  64. CreatTime string `json:"creatTime"`
  65. }
  66. type ProjectSummaryData struct {
  67. ProjectSummaryBaseData
  68. NumRepoPublic int64 `json:"numRepoPublic"`
  69. NumRepoPrivate int64 `json:"numRepoPrivate"`
  70. NumRepoFork int64 `json:"numRepoFork"`
  71. NumRepoMirror int64 `json:"numRepoMirror"`
  72. NumRepoSelf int64 `json:"numRepoSelf"`
  73. NumRepoOrgAdd int64 `json:"numRepoOrgAdd"`
  74. NumRepoNotOrgAdd int64 `json:"numRepoNotOrgAdd"`
  75. NumRepoOrg int64 `json:"numRepoOrg"`
  76. NumRepoNotOrg int64 `json:"numRepoNotOrg"`
  77. }
  78. type ProjectSummaryPeriodData struct {
  79. RecordBeginTime string `json:"recordBeginTime"`
  80. TotalCount int64 `json:"totalCount"`
  81. PageRecords []*ProjectSummaryBaseData `json:"pageRecords"`
  82. }
  83. func RestoreForkNumber(ctx *context.Context) {
  84. repos, err := models.GetAllRepositories()
  85. if err != nil {
  86. log.Error("GetAllRepositories failed: %v", err.Error())
  87. return
  88. }
  89. for _, repo := range repos {
  90. models.RestoreRepoStatFork(int64(repo.NumForks), repo.ID)
  91. }
  92. ctx.JSON(http.StatusOK, struct{}{})
  93. }
  94. func GetLatestProjectsSummaryData(ctx *context.Context) {
  95. stat, err := models.GetLatest2SummaryStatistic()
  96. data := ProjectSummaryData{}
  97. if err == nil && len(stat) > 0 {
  98. data.NumRepos = stat[0].NumRepos
  99. data.NumRepoOrg = stat[0].NumRepoOrg
  100. data.NumRepoNotOrg = stat[0].NumRepos - stat[0].NumRepoOrg
  101. data.NumRepoFork = stat[0].NumRepoFork
  102. data.NumRepoMirror = stat[0].NumRepoMirror
  103. data.NumRepoSelf = stat[0].NumRepoSelf
  104. data.NumRepoPrivate = stat[0].NumRepoPrivate
  105. data.NumRepoPublic = stat[0].NumRepoPublic
  106. data.CreatTime = stat[0].CreatedUnix.Format(UPDATE_TIME_FORMAT)
  107. if len(stat) == 2 {
  108. data.NumReposAdd = stat[0].NumRepos - stat[1].NumRepos
  109. data.NumRepoOrgAdd = stat[0].NumRepoOrg - stat[1].NumRepoOrg
  110. data.NumRepoNotOrgAdd = (stat[0].NumRepos - stat[0].NumRepoOrg) - (stat[1].NumRepos - stat[1].NumRepoOrg)
  111. data.NumRepoForkAdd = stat[0].NumRepoFork - stat[1].NumRepoFork
  112. data.NumRepoMirrorAdd = stat[0].NumRepoMirror - stat[1].NumRepoMirror
  113. data.NumRepoSelfAdd = stat[0].NumRepoSelf - stat[1].NumRepoSelf
  114. data.NumRepoPrivateAdd = stat[0].NumRepoPrivate - stat[1].NumRepoPrivate
  115. data.NumRepoPublicAdd = stat[0].NumRepoPublic - stat[1].NumRepoPublic
  116. }
  117. }
  118. ctx.JSON(200, data)
  119. }
  120. func GetProjectsSummaryData(ctx *context.Context) {
  121. var datas = make([]*ProjectSummaryBaseData, 0)
  122. recordBeginTime, err := getGrowthRecordBeginTime()
  123. if err != nil {
  124. log.Error("Can not get record begin time", err)
  125. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  126. return
  127. }
  128. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  129. beginTime = beginTime.AddDate(0, 0, -1)
  130. queryType := ctx.QueryTrim("type")
  131. var count int64
  132. if queryType == "all" || queryType == "current_year" {
  133. dates := getEndOfMonthDates(beginTime, endTime)
  134. count, _ = models.GetSummaryStatisticByDateCount(dates)
  135. stats, err := models.GetAllSummaryStatisticByDates(dates)
  136. if err != nil {
  137. log.Warn("can not get summary data", err)
  138. } else {
  139. for i, v := range stats {
  140. if i == 0 {
  141. continue
  142. }
  143. data := ProjectSummaryBaseData{}
  144. setStatisticsData(&data, v, stats[i-1])
  145. createTime, _ := time.Parse(DATE_FORMAT, v.Date)
  146. data.CreatTime = createTime.Format(MONTH_FORMAT)
  147. datas = append(datas, &data)
  148. }
  149. }
  150. } else {
  151. count, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime)
  152. stats, err := models.GetAllSummaryStatisticByTime(beginTime, endTime)
  153. if err != nil {
  154. log.Warn("can not get summary data", err)
  155. } else {
  156. for i, v := range stats {
  157. if i == 0 {
  158. continue
  159. }
  160. data := ProjectSummaryBaseData{}
  161. setStatisticsData(&data, v, stats[i-1])
  162. data.CreatTime = v.Date
  163. datas = append(datas, &data)
  164. }
  165. }
  166. }
  167. projectSummaryPeriodData := ProjectSummaryPeriodData{
  168. TotalCount: count - 1,
  169. RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
  170. PageRecords: reverse(datas),
  171. }
  172. ctx.JSON(200, projectSummaryPeriodData)
  173. }
  174. func reverse(datas []*ProjectSummaryBaseData) []*ProjectSummaryBaseData {
  175. for i := 0; i < len(datas)/2; i++ {
  176. j := len(datas) - i - 1
  177. datas[i], datas[j] = datas[j], datas[i]
  178. }
  179. return datas
  180. }
  181. func setStatisticsData(data *ProjectSummaryBaseData, v *models.SummaryStatistic, stats *models.SummaryStatistic) {
  182. data.NumReposAdd = v.NumRepos - stats.NumRepos
  183. data.NumRepoPublicAdd = v.NumRepoPublic - stats.NumRepoPublic
  184. data.NumRepoPrivateAdd = v.NumRepoPrivate - stats.NumRepoPrivate
  185. data.NumRepoMirrorAdd = v.NumRepoMirror - stats.NumRepoMirror
  186. data.NumRepoForkAdd = v.NumRepoFork - stats.NumRepoFork
  187. data.NumRepoSelfAdd = v.NumRepoSelf - stats.NumRepoSelf
  188. data.NumRepos = v.NumRepos
  189. }
  190. func getEndOfMonthDates(beginTime time.Time, endTime time.Time) []string {
  191. var dates = []string{}
  192. date := endOfMonth(beginTime.AddDate(0, -1, 0))
  193. dates = append(dates, date.Format(DATE_FORMAT))
  194. tempDate := endOfMonth(beginTime)
  195. for {
  196. if tempDate.Before(endTime) {
  197. dates = append(dates, tempDate.Format(DATE_FORMAT))
  198. tempDate = endOfMonth(tempDate.AddDate(0, 0, 1))
  199. } else {
  200. break
  201. }
  202. }
  203. dates = append(dates, endTime.AddDate(0, 0, -1).Format(DATE_FORMAT))
  204. return dates
  205. }
  206. func endOfMonth(date time.Time) time.Time {
  207. return date.AddDate(0, 1, -date.Day())
  208. }
  209. func GetAllProjectsPeriodStatistics(ctx *context.Context) {
  210. recordBeginTime, err := getRecordBeginTime()
  211. if err != nil {
  212. log.Error("Can not get record begin time", err)
  213. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  214. return
  215. }
  216. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  217. if err != nil {
  218. log.Error("Parameter is wrong", err)
  219. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
  220. return
  221. }
  222. q := ctx.QueryTrim("q")
  223. page := ctx.QueryInt("page")
  224. if page <= 0 {
  225. page = 1
  226. }
  227. pageSize := ctx.QueryInt("pagesize")
  228. if pageSize <= 0 {
  229. pageSize = DEFAULT_PAGE_SIZE
  230. }
  231. orderBy := getOrderBy(ctx)
  232. latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime()
  233. if err != nil {
  234. log.Error("Can not query the last updated time.", err)
  235. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  236. return
  237. }
  238. countSql := generateCountSql(beginTime, endTime, latestDate, q)
  239. total, err := models.CountRepoStatByRawSql(countSql)
  240. if err != nil {
  241. log.Error("Can not query total count.", err)
  242. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  243. return
  244. }
  245. sql := generateSqlByType(ctx, beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  246. projectsPeriodData := ProjectsPeriodData{
  247. RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
  248. PageSize: pageSize,
  249. TotalPage: getTotalPage(total, pageSize),
  250. TotalCount: total,
  251. LastUpdatedTime: latestUpdatedTime,
  252. PageRecords: models.GetRepoStatisticByRawSql(sql),
  253. }
  254. ctx.JSON(http.StatusOK, projectsPeriodData)
  255. }
  256. func generateSqlByType(ctx *context.Context, beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  257. sql := ""
  258. if ctx.QueryTrim("type") == "all" {
  259. sql = generateTypeAllSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  260. } else {
  261. sql = generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)
  262. }
  263. return sql
  264. }
  265. func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) {
  266. recordBeginTime, err := getRecordBeginTime()
  267. if err != nil {
  268. log.Error("Can not get record begin time", err)
  269. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  270. return
  271. }
  272. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  273. if err != nil {
  274. log.Error("Parameter is wrong", err)
  275. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
  276. return
  277. }
  278. q := ctx.QueryTrim("q")
  279. page := ctx.QueryInt("page")
  280. if page <= 0 {
  281. page = 1
  282. }
  283. pageSize := 1000
  284. orderBy := getOrderBy(ctx)
  285. _, latestDate, err := models.GetRepoStatLastUpdatedTime()
  286. if err != nil {
  287. log.Error("Can not query the last updated time.", err)
  288. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  289. return
  290. }
  291. countSql := generateCountSql(beginTime, endTime, latestDate, q)
  292. total, err := models.CountRepoStatByRawSql(countSql)
  293. if err != nil {
  294. log.Error("Can not query total count.", err)
  295. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  296. return
  297. }
  298. var projectAnalysis = ctx.Tr("repo.repo_stat_inspect")
  299. fileName := getFileName(ctx, beginTime, endTime, projectAnalysis)
  300. totalPage := getTotalPage(total, pageSize)
  301. f := excelize.NewFile()
  302. index := f.NewSheet(projectAnalysis)
  303. f.DeleteSheet("Sheet1")
  304. for k, v := range allProjectsPeroidHeader(ctx) {
  305. f.SetCellValue(projectAnalysis, k, v)
  306. }
  307. var row = 2
  308. for i := 0; i <= totalPage; i++ {
  309. pageRecords := models.GetRepoStatisticByRawSql(generateSqlByType(ctx, beginTime, endTime, latestDate, q, orderBy, i+1, pageSize))
  310. for _, record := range pageRecords {
  311. for k, v := range allProjectsPeroidValues(row, record, ctx) {
  312. f.SetCellValue(projectAnalysis, k, v)
  313. }
  314. row++
  315. }
  316. }
  317. f.SetActiveSheet(index)
  318. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
  319. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  320. f.WriteTo(ctx.Resp)
  321. }
  322. func GetProjectsSummaryDataFile(ctx *context.Context) {
  323. recordBeginTime, err := getGrowthRecordBeginTime()
  324. if err != nil {
  325. log.Error("Can not get record begin time", err)
  326. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  327. return
  328. }
  329. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  330. beginTime = beginTime.AddDate(0, 0, -1)
  331. if err != nil {
  332. log.Error("Parameter is wrong", err)
  333. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
  334. return
  335. }
  336. page := ctx.QueryInt("page")
  337. if page <= 0 {
  338. page = 1
  339. }
  340. pageSize := 100
  341. if err != nil {
  342. log.Error("Can not query the last updated time.", err)
  343. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  344. return
  345. }
  346. var projectAnalysis = ctx.Tr("repo.repo_stat_develop")
  347. fileName := getSummaryFileName(ctx, beginTime, endTime, projectAnalysis)
  348. f := excelize.NewFile()
  349. index := f.NewSheet(projectAnalysis)
  350. f.DeleteSheet("Sheet1")
  351. for k, v := range allProjectsPeriodSummaryHeader(ctx) {
  352. f.SetCellValue(projectAnalysis, k, v)
  353. }
  354. var total int64
  355. queryType := ctx.QueryTrim("type")
  356. var datas = make([]*ProjectSummaryBaseData, 0)
  357. if queryType == "all" || queryType == "current_year" {
  358. dates := getEndOfMonthDates(beginTime, endTime)
  359. total, _ = models.GetSummaryStatisticByDateCount(dates)
  360. totalPage := getTotalPage(total, pageSize)
  361. for i := 0; i < totalPage; i++ {
  362. stats, err := models.GetSummaryStatisticByDates(dates, i+1, pageSize)
  363. if err != nil {
  364. log.Warn("can not get summary data", err)
  365. } else {
  366. for j, v := range stats {
  367. if j == 0 {
  368. continue
  369. }
  370. data := ProjectSummaryBaseData{}
  371. setStatisticsData(&data, v, stats[j-1])
  372. createTime, _ := time.Parse(DATE_FORMAT, v.Date)
  373. data.CreatTime = createTime.Format(MONTH_FORMAT)
  374. datas = append(datas, &data)
  375. }
  376. }
  377. }
  378. } else {
  379. total, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime)
  380. totalPage := getTotalPage(total, pageSize)
  381. for i := 0; i < totalPage; i++ {
  382. stats, err := models.GetSummaryStatisticByTime(beginTime, endTime, i+1, pageSize)
  383. if err != nil {
  384. log.Warn("can not get summary data", err)
  385. } else {
  386. for j, v := range stats {
  387. if j == 0 {
  388. continue
  389. }
  390. data := ProjectSummaryBaseData{}
  391. setStatisticsData(&data, v, stats[j-1])
  392. data.CreatTime = v.Date
  393. datas = append(datas, &data)
  394. }
  395. }
  396. }
  397. }
  398. row := 2
  399. datas = reverse(datas)
  400. for _, data := range datas {
  401. for k, v := range allProjectsPeriodSummaryValues(row, data, ctx) {
  402. f.SetCellValue(projectAnalysis, k, v)
  403. }
  404. row++
  405. }
  406. f.SetActiveSheet(index)
  407. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
  408. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  409. f.WriteTo(ctx.Resp)
  410. }
  411. func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) {
  412. page := ctx.QueryInt("page")
  413. if page <= 0 {
  414. page = 1
  415. }
  416. pageSize := 1000
  417. _, latestDate, err := models.GetRepoStatLastUpdatedTime()
  418. if err != nil {
  419. log.Error("Can not query the last updated time.", err)
  420. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
  421. return
  422. }
  423. date := ctx.QueryTrim("date")
  424. if date == "" {
  425. date = latestDate
  426. }
  427. countSql := generateOpenICountSql(date)
  428. total, err := models.CountRepoStatByRawSql(countSql)
  429. if err != nil {
  430. log.Error("Can not query total count.", err)
  431. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
  432. return
  433. }
  434. var projectAnalysis = ctx.Tr("repo.repo_stat_inspect")
  435. fileName := "项目分析_OPENI_" + date + ".xlsx"
  436. totalPage := getTotalPage(total, pageSize)
  437. f := excelize.NewFile()
  438. index := f.NewSheet(projectAnalysis)
  439. f.DeleteSheet("Sheet1")
  440. for k, v := range allProjectsOpenIHeader() {
  441. f.SetCellValue(projectAnalysis, k, v)
  442. }
  443. var row = 2
  444. for i := 0; i <= totalPage; i++ {
  445. pageRecords := models.GetRepoStatisticByRawSql(generateTypeAllOpenISql(date, i+1, pageSize))
  446. for _, record := range pageRecords {
  447. for k, v := range allProjectsOpenIValues(row, record, ctx) {
  448. f.SetCellValue(projectAnalysis, k, v)
  449. }
  450. row++
  451. }
  452. }
  453. f.SetActiveSheet(index)
  454. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName))
  455. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  456. f.WriteTo(ctx.Resp)
  457. }
  458. func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string {
  459. baseName := projectAnalysis + "_"
  460. if ctx.QueryTrim("q") != "" {
  461. baseName = baseName + ctx.QueryTrim("q") + "_"
  462. }
  463. if ctx.QueryTrim("type") == "all" {
  464. baseName = baseName + ctx.Tr("repo.all")
  465. } else if ctx.QueryTrim("type") == "last_month" {
  466. baseName = baseName + beginTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -2).Format(EXCEL_DATE_FORMAT)
  467. } else {
  468. baseName = baseName + beginTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT)
  469. }
  470. frontName := baseName + ".xlsx"
  471. return frontName
  472. }
  473. func getSummaryFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string {
  474. baseName := projectAnalysis + "_"
  475. if ctx.QueryTrim("type") == "all" {
  476. baseName = baseName + ctx.Tr("repo.all")
  477. } else if ctx.QueryTrim("type") == "current_year" {
  478. baseName = baseName + ctx.Tr("repo.current_year")
  479. } else if ctx.QueryTrim("type") == "last_month" {
  480. baseName = baseName + beginTime.Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -2).Format(EXCEL_DATE_FORMAT)
  481. } else {
  482. baseName = baseName + beginTime.Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT)
  483. }
  484. frontName := baseName + ".xlsx"
  485. return frontName
  486. }
  487. func allProjectsPeroidHeader(ctx *context.Context) map[string]string {
  488. 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"),
  489. "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"), "P1": ctx.Tr("admin.repos.isFork"), "Q1": ctx.Tr("admin.repos.isMirror"), "R1": ctx.Tr("admin.repos.create")}
  490. }
  491. func allProjectsPeriodSummaryHeader(ctx *context.Context) map[string]string {
  492. return map[string]string{"A1": ctx.Tr("repo.date"), "B1": ctx.Tr("repo.repo_add"), "C1": ctx.Tr("repo.repo_total"), "D1": ctx.Tr("repo.repo_public_add"), "E1": ctx.Tr("repo.repo_private_add"), "F1": ctx.Tr("repo.repo_self_add"), "G1": ctx.Tr("repo.repo_fork_add"), "H1": ctx.Tr("repo.repo_mirror_add")}
  493. }
  494. func allProjectsPeriodSummaryValues(row int, rs *ProjectSummaryBaseData, ctx *context.Context) map[string]string {
  495. return map[string]string{getCellName("A", row): rs.CreatTime, getCellName("B", row): strconv.FormatInt(rs.NumReposAdd, 10), getCellName("C", row): strconv.FormatInt(rs.NumRepos, 10), getCellName("D", row): strconv.FormatInt(rs.NumRepoPublicAdd, 10), getCellName("E", row): strconv.FormatInt(rs.NumRepoPrivateAdd, 10),
  496. getCellName("F", row): strconv.FormatInt(rs.NumRepoSelfAdd, 10), getCellName("G", row): strconv.FormatInt(rs.NumRepoForkAdd, 10), getCellName("H", row): strconv.FormatInt(rs.NumRepoMirrorAdd, 10),
  497. }
  498. }
  499. func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string {
  500. 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): getBoolDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
  501. 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),
  502. 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),
  503. getCellName("N", row): strconv.FormatInt(rs.NumClosedIssues, 10), getCellName("O", row): strconv.FormatInt(rs.NumContributor, 10), getCellName("P", row): getBoolDisplay(rs.IsFork, ctx), getCellName("Q", row): getBoolDisplay(rs.IsMirror, ctx), getCellName("R", row): time.Unix(int64(rs.RepoCreatedUnix), 0).Format(CREATE_TIME_FORMAT),
  504. }
  505. }
  506. func allProjectsOpenIHeader() map[string]string {
  507. return map[string]string{"A1": "ID", "B1": "项目名称", "C1": "拥有者", "D1": "私有", "E1": "OpenI指数",
  508. "F1": "影响力", "G1": "成熟度", "H1": "活跃度", "I1": "项目健康度", "J1": "团队健康度", "K1": "项目发展趋势",
  509. "L1": "关注数", "M1": "点赞数", "N1": "派生数", "O1": "代码下载量", "P1": "评论数", "Q1": "浏览量", "R1": "已解决任务数", "S1": "版本发布数量", "T1": "有效开发年龄",
  510. "U1": "数据集", "V1": "模型数", "W1": "百科页面数量", "X1": "提交数", "Y1": "任务数", "Z1": "PR数", "AA1": "版本发布数量", "AB1": "任务完成比例", "AC1": "贡献者数", "AD1": "关键贡献者数",
  511. "AE1": "新人增长量", "AF1": "代码规模增长量", "AG1": "任务增长量", "AH1": "新人增长量", "AI1": "提交增长量", "AJ1": "评论增长量", "AK1": "迁移", "AL1": "镜像", "AM1": "项目创建时间",
  512. }
  513. }
  514. func allProjectsOpenIValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string {
  515. 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): getBoolDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64),
  516. 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),
  517. 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),
  518. 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),
  519. 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),
  520. 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),
  521. 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),
  522. 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), getCellName("AK", row): getBoolDisplay(rs.IsFork, ctx), getCellName("AL", row): getBoolDisplay(rs.IsMirror, ctx), getCellName("AM", row): time.Unix(int64(rs.RepoCreatedUnix), 0).Format(CREATE_TIME_FORMAT),
  523. }
  524. }
  525. func getCellName(col string, row int) string {
  526. return col + strconv.Itoa(row)
  527. }
  528. func getBoolDisplay(value bool, ctx *context.Context) string {
  529. if value {
  530. return ctx.Tr("admin.repos.yes")
  531. } else {
  532. return ctx.Tr("admin.repos.no")
  533. }
  534. }
  535. func GetProjectLatestStatistics(ctx *context.Context) {
  536. repoId := ctx.Params(":id")
  537. recordBeginTime, err := getRecordBeginTime()
  538. if err != nil {
  539. log.Error("Can not get record begin time", err)
  540. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  541. return
  542. }
  543. latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId)
  544. repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)
  545. repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt)
  546. if err != nil {
  547. log.Error("Can not get the repo statistics "+repoId, err)
  548. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error"))
  549. return
  550. }
  551. repository, err := models.GetRepositoryByID(repoIdInt)
  552. if err != nil {
  553. log.Error("Can not get the repo info "+repoId, err)
  554. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error"))
  555. return
  556. }
  557. projectLatestData := ProjectLatestData{
  558. RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
  559. CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT),
  560. LastUpdatedTime: latestUpdatedTime,
  561. OpenI: repoStat.RadarTotal,
  562. Comment: repoStat.NumComments,
  563. View: repoStat.NumVisits,
  564. Download: repoStat.NumDownloads,
  565. IssueClosedRatio: repoStat.IssueFixedRate,
  566. Impact: repoStat.Impact,
  567. Completeness: repoStat.Completeness,
  568. Liveness: repoStat.Liveness,
  569. ProjectHealth: repoStat.ProjectHealth,
  570. TeamHealth: repoStat.TeamHealth,
  571. Growth: repoStat.Growth,
  572. Description: repository.Description,
  573. }
  574. contributors, err := models.GetTop10Contributor(repository.RepoPath())
  575. if err != nil {
  576. log.Error("can not get contributors", err)
  577. }
  578. users := make([]UserInfo, 0)
  579. for _, contributor := range contributors {
  580. mode := repository.GetCollaboratorMode(contributor.UserId)
  581. if mode == -1 {
  582. if contributor.IsAdmin {
  583. mode = int(models.AccessModeAdmin)
  584. }
  585. if contributor.UserId == repository.OwnerID {
  586. mode = int(models.AccessModeOwner)
  587. }
  588. }
  589. pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId)
  590. userInfo := UserInfo{
  591. User: contributor.Committer,
  592. Commit: contributor.CommitCnt,
  593. Mode: mode,
  594. PR: pr,
  595. RelAvatarLink: contributor.RelAvatarLink,
  596. Email: contributor.Email,
  597. }
  598. users = append(users, userInfo)
  599. }
  600. projectLatestData.Top10 = users
  601. ctx.JSON(http.StatusOK, projectLatestData)
  602. }
  603. func GetProjectPeriodStatistics(ctx *context.Context) {
  604. repoId := ctx.Params(":id")
  605. recordBeginTime, err := getRecordBeginTime()
  606. if err != nil {
  607. log.Error("Can not get record begin time", err)
  608. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  609. return
  610. }
  611. repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)
  612. if err != nil {
  613. log.Error("Can not get record begin time", err)
  614. ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
  615. return
  616. }
  617. beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
  618. isOpenI := ctx.QueryBool("openi")
  619. var repositorys []*models.RepoStatistic
  620. if isOpenI {
  621. repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt))
  622. } else {
  623. repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt))
  624. }
  625. ctx.JSON(http.StatusOK, repositorys)
  626. }
  627. func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string {
  628. sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" +
  629. " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  630. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " order by created_unix"
  631. return sql
  632. }
  633. func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string {
  634. sql := "SELECT date, num_visits,num_downloads_added as num_downloads,num_commits_added as num_commits FROM repo_statistic" +
  635. " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  636. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " order by created_unix desc"
  637. return sql
  638. }
  639. func generateCountSql(beginTime time.Time, endTime time.Time, latestDate string, q string) string {
  640. countSql := "SELECT count(*) FROM " +
  641. "(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  642. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  643. "(SELECT repo_id,name,alias,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" +
  644. " where A.repo_id=B.repo_id"
  645. if q != "" {
  646. countSql = countSql + " and LOWER(B.alias) like '%" + strings.ToLower(q) + "%'"
  647. }
  648. return countSql
  649. }
  650. func generateOpenICountSql(latestDate string) string {
  651. countSql := "SELECT count(*) FROM " +
  652. "public.repo_statistic where date='" + latestDate + "'"
  653. return countSql
  654. }
  655. func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  656. sql := "SELECT A.repo_id,name,alias,owner_name,is_private,is_mirror,is_fork,repo_created_unix,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " +
  657. "(SELECT repo_id,sum(num_visits) as num_visits " +
  658. " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  659. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  660. "(SELECT repo_id,name,alias,owner_name,is_private,is_mirror,is_fork,repo_created_unix,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" +
  661. " where A.repo_id=B.repo_id"
  662. if q != "" {
  663. sql = sql + " and LOWER(alias) like '%" + strings.ToLower(q) + "%'"
  664. }
  665. sql = sql + " order by " + orderBy + " desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  666. return sql
  667. }
  668. func generateTypeAllOpenISql(latestDate string, page int, pageSize int) string {
  669. 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,is_mirror,is_fork,repo_created_unix, owner_name FROM " +
  670. " public.repo_statistic where date='" + latestDate + "'"
  671. sql = sql + " order by radar_total desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  672. return sql
  673. }
  674. func generatePageSql(beginTime time.Time, endTime time.Time, latestDate string, q string, orderBy string, page int, pageSize int) string {
  675. sql := "SELECT A.repo_id,name,alias,owner_name,is_private,is_mirror,is_fork,repo_created_unix,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " +
  676. "(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 " +
  677. " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
  678. " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
  679. "(SELECT repo_id,name,alias,owner_name,is_private,is_mirror,is_fork,repo_created_unix,radar_total from public.repo_statistic where date='" + latestDate + "') B" +
  680. " where A.repo_id=B.repo_id"
  681. if q != "" {
  682. sql = sql + " and LOWER(B.alias) like '%" + strings.ToLower(q) + "%'"
  683. }
  684. sql = sql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
  685. return sql
  686. }
  687. func getOrderBy(ctx *context.Context) string {
  688. orderBy := ""
  689. switch ctx.Query("sort") {
  690. case "openi":
  691. orderBy = "B.radar_total"
  692. case "view":
  693. orderBy = "A.num_visits"
  694. case "download":
  695. orderBy = "A.num_downloads"
  696. case "pr":
  697. orderBy = "A.num_pulls"
  698. case "commit":
  699. orderBy = "A.num_commits"
  700. case "watch":
  701. orderBy = "A.num_watches"
  702. case "star":
  703. orderBy = "A.num_stars"
  704. case "fork":
  705. orderBy = "A.num_forks"
  706. case "issue":
  707. orderBy = "A.num_issues"
  708. case "issue_closed":
  709. orderBy = "A.num_closed_issues"
  710. case "contributor":
  711. orderBy = "A.num_contributor"
  712. default:
  713. orderBy = "B.radar_total"
  714. }
  715. return orderBy
  716. }
  717. func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) {
  718. queryType := ctx.QueryTrim("type")
  719. now := time.Now()
  720. recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1)
  721. beginTimeStr := ctx.QueryTrim("beginTime")
  722. endTimeStr := ctx.QueryTrim("endTime")
  723. var beginTime time.Time
  724. var endTime time.Time
  725. var err error
  726. if queryType != "" {
  727. if queryType == "all" {
  728. beginTime = recordBeginTimeTemp
  729. endTime = now
  730. } else if queryType == "yesterday" {
  731. endTime = now
  732. beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())
  733. } else if queryType == "current_week" {
  734. beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+2) //begin from monday
  735. beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
  736. endTime = now
  737. } else if queryType == "current_month" {
  738. endTime = now
  739. beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location())
  740. } else if queryType == "monthly" {
  741. endTime = now
  742. beginTime = now.AddDate(0, -1, 1)
  743. beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
  744. } else if queryType == "current_year" {
  745. endTime = now
  746. beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location())
  747. } else if queryType == "last_month" {
  748. lastMonthTime := now.AddDate(0, -1, 0)
  749. beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location())
  750. endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location())
  751. } else {
  752. return now, now, fmt.Errorf("The value of type parameter is wrong.")
  753. }
  754. } else {
  755. if beginTimeStr == "" || endTimeStr == "" {
  756. //如果查询类型和开始时间结束时间都未设置,按queryType=all处理
  757. beginTime = recordBeginTimeTemp
  758. endTime = now
  759. } else {
  760. beginTime, err = time.ParseInLocation("2006-01-02", beginTimeStr, time.Local)
  761. if err != nil {
  762. return now, now, err
  763. }
  764. endTime, err = time.ParseInLocation("2006-01-02", endTimeStr, time.Local)
  765. if err != nil {
  766. return now, now, err
  767. }
  768. beginTime = beginTime.AddDate(0, 0, 1)
  769. endTime = endTime.AddDate(0, 0, 1)
  770. }
  771. }
  772. if beginTime.Before(recordBeginTimeTemp) {
  773. beginTime = recordBeginTimeTemp
  774. }
  775. return beginTime, endTime, nil
  776. }
  777. func getRecordBeginTime() (time.Time, error) {
  778. return time.ParseInLocation(DATE_FORMAT, setting.RadarMap.RecordBeginTime, time.Local)
  779. }
  780. func getGrowthRecordBeginTime() (time.Time, error) {
  781. return time.ParseInLocation(DATE_FORMAT, setting.RadarMap.GrowthBeginTime, time.Local)
  782. }
  783. func getTotalPage(total int64, pageSize int) int {
  784. another := 0
  785. if int(total)%pageSize != 0 {
  786. another = 1
  787. }
  788. return int(total)/pageSize + another
  789. }
  790. func ProjectNumVisit(ctx *context.APIContext) {
  791. var (
  792. err error
  793. )
  794. var userName = ctx.Query("user")
  795. var projectName = ctx.Query("project")
  796. var beginTime = ctx.Query("begintime")
  797. var endTime = ctx.Query("endtime")
  798. var ProjectNumVisits int
  799. ProjectNumVisits, err = repository.AppointProjectView(userName, projectName, beginTime, endTime) //访问量
  800. if err != nil {
  801. ctx.NotFound(err)
  802. }
  803. log.Info("ProjectNumVisits is:", ProjectNumVisits)
  804. ctx.JSON(http.StatusOK, map[string]interface{}{
  805. "ProjectNumVisits": ProjectNumVisits,
  806. "StatusOK": 0,
  807. })
  808. }