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

440 lines
11 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "fmt"
  7. "net/url"
  8. "os"
  9. "path"
  10. "strings"
  11. "github.com/Unknwon/com"
  12. "github.com/gogits/gogs/models"
  13. "github.com/gogits/gogs/modules/auth"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/git"
  16. "github.com/gogits/gogs/modules/log"
  17. "github.com/gogits/gogs/modules/middleware"
  18. "github.com/gogits/gogs/modules/setting"
  19. )
  20. const (
  21. CREATE base.TplName = "repo/create"
  22. MIGRATE base.TplName = "repo/migrate"
  23. FORK base.TplName = "repo/fork"
  24. )
  25. func checkContextUser(ctx *middleware.Context, uid int64) (*models.User, error) {
  26. ctxUser := ctx.User
  27. if uid > 0 {
  28. org, err := models.GetUserById(uid)
  29. if err != models.ErrUserNotExist {
  30. if err != nil {
  31. return nil, fmt.Errorf("GetUserById: %v", err)
  32. }
  33. ctxUser = org
  34. }
  35. }
  36. return ctxUser, nil
  37. }
  38. func Create(ctx *middleware.Context) {
  39. ctx.Data["Title"] = ctx.Tr("new_repo")
  40. // Give default value for template to render.
  41. ctx.Data["gitignore"] = "0"
  42. ctx.Data["license"] = "0"
  43. ctx.Data["Gitignores"] = models.Gitignores
  44. ctx.Data["Licenses"] = models.Licenses
  45. ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org"))
  46. if err != nil {
  47. ctx.Handle(500, "checkContextUser", err)
  48. return
  49. }
  50. ctx.Data["ContextUser"] = ctxUser
  51. if err := ctx.User.GetOrganizations(); err != nil {
  52. ctx.Handle(500, "GetOrganizations", err)
  53. return
  54. }
  55. ctx.Data["Orgs"] = ctx.User.Orgs
  56. ctx.HTML(200, CREATE)
  57. }
  58. func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
  59. ctx.Data["Title"] = ctx.Tr("new_repo")
  60. ctx.Data["Gitignores"] = models.Gitignores
  61. ctx.Data["Licenses"] = models.Licenses
  62. ctxUser := ctx.User
  63. // Not equal means current user is an organization.
  64. if form.Uid != ctx.User.Id {
  65. var err error
  66. ctxUser, err = checkContextUser(ctx, form.Uid)
  67. if err != nil {
  68. ctx.Handle(500, "checkContextUser", err)
  69. return
  70. }
  71. }
  72. ctx.Data["ContextUser"] = ctxUser
  73. if err := ctx.User.GetOrganizations(); err != nil {
  74. ctx.Handle(500, "GetOrganizations", err)
  75. return
  76. }
  77. ctx.Data["Orgs"] = ctx.User.Orgs
  78. if ctx.HasError() {
  79. ctx.HTML(200, CREATE)
  80. return
  81. }
  82. if ctxUser.IsOrganization() {
  83. // Check ownership of organization.
  84. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  85. ctx.Error(403)
  86. return
  87. }
  88. }
  89. repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description,
  90. form.Gitignore, form.License, form.Private, false, form.AutoInit)
  91. if err == nil {
  92. log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name)
  93. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  94. return
  95. } else if err == models.ErrRepoAlreadyExist {
  96. ctx.Data["Err_RepoName"] = true
  97. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), CREATE, &form)
  98. return
  99. } else if err == models.ErrRepoNameIllegal {
  100. ctx.Data["Err_RepoName"] = true
  101. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), CREATE, &form)
  102. return
  103. }
  104. if repo != nil {
  105. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  106. log.Error(4, "DeleteRepository: %v", errDelete)
  107. }
  108. }
  109. ctx.Handle(500, "CreatePost", err)
  110. }
  111. func Migrate(ctx *middleware.Context) {
  112. ctx.Data["Title"] = ctx.Tr("new_migrate")
  113. ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org"))
  114. if err != nil {
  115. ctx.Handle(500, "checkContextUser", err)
  116. return
  117. }
  118. ctx.Data["ContextUser"] = ctxUser
  119. if err := ctx.User.GetOrganizations(); err != nil {
  120. ctx.Handle(500, "GetOrganizations", err)
  121. return
  122. }
  123. ctx.Data["Orgs"] = ctx.User.Orgs
  124. ctx.HTML(200, MIGRATE)
  125. }
  126. func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
  127. ctx.Data["Title"] = ctx.Tr("new_migrate")
  128. ctxUser := ctx.User
  129. // Not equal means current user is an organization.
  130. if form.Uid != ctx.User.Id {
  131. var err error
  132. ctxUser, err = checkContextUser(ctx, form.Uid)
  133. if err != nil {
  134. ctx.Handle(500, "checkContextUser", err)
  135. return
  136. }
  137. }
  138. ctx.Data["ContextUser"] = ctxUser
  139. if err := ctx.User.GetOrganizations(); err != nil {
  140. ctx.Handle(500, "GetOrganizations", err)
  141. return
  142. }
  143. ctx.Data["Orgs"] = ctx.User.Orgs
  144. if ctx.HasError() {
  145. ctx.HTML(200, MIGRATE)
  146. return
  147. }
  148. if ctxUser.IsOrganization() {
  149. // Check ownership of organization.
  150. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  151. ctx.Error(403)
  152. return
  153. }
  154. }
  155. u, err := url.Parse(form.HttpsUrl)
  156. if err != nil || u.Scheme != "https" {
  157. ctx.Data["Err_HttpsUrl"] = true
  158. ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
  159. return
  160. }
  161. if len(form.AuthUserName) > 0 || len(form.AuthPasswd) > 0 {
  162. u.User = url.UserPassword(form.AuthUserName, form.AuthPasswd)
  163. }
  164. repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private,
  165. form.Mirror, u.String())
  166. if err == nil {
  167. log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
  168. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
  169. return
  170. } else if err == models.ErrRepoAlreadyExist {
  171. ctx.Data["Err_RepoName"] = true
  172. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), MIGRATE, &form)
  173. return
  174. } else if err == models.ErrRepoNameIllegal {
  175. ctx.Data["Err_RepoName"] = true
  176. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), MIGRATE, &form)
  177. return
  178. }
  179. if repo != nil {
  180. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  181. log.Error(4, "DeleteRepository: %v", errDelete)
  182. }
  183. }
  184. if strings.Contains(err.Error(), "Authentication failed") {
  185. ctx.Data["Err_Auth"] = true
  186. ctx.RenderWithErr(ctx.Tr("form.auth_failed", err), MIGRATE, &form)
  187. return
  188. }
  189. ctx.Handle(500, "MigratePost", err)
  190. }
  191. func getForkRepository(ctx *middleware.Context) (*models.Repository, error) {
  192. forkId := ctx.QueryInt64("fork_id")
  193. ctx.Data["ForkId"] = forkId
  194. forkRepo, err := models.GetRepositoryById(forkId)
  195. if err != nil {
  196. return nil, fmt.Errorf("GetRepositoryById: %v", err)
  197. }
  198. ctx.Data["repo_name"] = forkRepo.Name
  199. ctx.Data["desc"] = forkRepo.Description
  200. if err = forkRepo.GetOwner(); err != nil {
  201. return nil, fmt.Errorf("GetOwner: %v", err)
  202. }
  203. ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name
  204. return forkRepo, nil
  205. }
  206. func Fork(ctx *middleware.Context) {
  207. ctx.Data["Title"] = ctx.Tr("new_fork")
  208. if _, err := getForkRepository(ctx); err != nil {
  209. if err == models.ErrRepoNotExist {
  210. ctx.Redirect(setting.AppSubUrl + "/")
  211. } else {
  212. ctx.Handle(500, "getForkRepository", err)
  213. }
  214. return
  215. }
  216. // FIXME: maybe sometime can directly fork to organization?
  217. ctx.Data["ContextUser"] = ctx.User
  218. if err := ctx.User.GetOrganizations(); err != nil {
  219. ctx.Handle(500, "GetOrganizations", err)
  220. return
  221. }
  222. ctx.Data["Orgs"] = ctx.User.Orgs
  223. ctx.HTML(200, FORK)
  224. }
  225. func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
  226. ctx.Data["Title"] = ctx.Tr("new_fork")
  227. forkRepo, err := getForkRepository(ctx)
  228. if err != nil {
  229. if err == models.ErrRepoNotExist {
  230. ctx.Redirect(setting.AppSubUrl + "/")
  231. } else {
  232. ctx.Handle(500, "getForkRepository", err)
  233. }
  234. return
  235. }
  236. ctxUser := ctx.User
  237. // Not equal means current user is an organization.
  238. if form.Uid != ctx.User.Id {
  239. var err error
  240. ctxUser, err = checkContextUser(ctx, form.Uid)
  241. if err != nil {
  242. ctx.Handle(500, "checkContextUser", err)
  243. return
  244. }
  245. }
  246. ctx.Data["ContextUser"] = ctxUser
  247. if err := ctx.User.GetOrganizations(); err != nil {
  248. ctx.Handle(500, "GetOrganizations", err)
  249. return
  250. }
  251. ctx.Data["Orgs"] = ctx.User.Orgs
  252. if ctx.HasError() {
  253. ctx.HTML(200, CREATE)
  254. return
  255. }
  256. if ctxUser.IsOrganization() {
  257. // Check ownership of organization.
  258. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  259. ctx.Error(403)
  260. return
  261. }
  262. }
  263. repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description)
  264. if err == nil {
  265. log.Trace("Repository forked: %s/%s", ctxUser.Name, repo.Name)
  266. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  267. return
  268. } else if err == models.ErrRepoAlreadyExist {
  269. ctx.Data["Err_RepoName"] = true
  270. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), FORK, &form)
  271. return
  272. } else if err == models.ErrRepoNameIllegal {
  273. ctx.Data["Err_RepoName"] = true
  274. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), CREATE, &form)
  275. return
  276. }
  277. if repo != nil {
  278. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  279. log.Error(4, "DeleteRepository: %v", errDelete)
  280. }
  281. }
  282. ctx.Handle(500, "ForkPost", err)
  283. }
  284. func Action(ctx *middleware.Context) {
  285. var err error
  286. switch ctx.Params(":action") {
  287. case "watch":
  288. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  289. case "unwatch":
  290. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  291. case "star":
  292. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  293. case "unstar":
  294. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  295. case "desc":
  296. if !ctx.Repo.IsOwner {
  297. ctx.Error(404)
  298. return
  299. }
  300. ctx.Repo.Repository.Description = ctx.Query("desc")
  301. ctx.Repo.Repository.Website = ctx.Query("site")
  302. err = models.UpdateRepository(ctx.Repo.Repository)
  303. }
  304. if err != nil {
  305. log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
  306. ctx.JSON(200, map[string]interface{}{
  307. "ok": false,
  308. "err": err.Error(),
  309. })
  310. return
  311. }
  312. ctx.Redirect(ctx.Repo.RepoLink)
  313. return
  314. ctx.JSON(200, map[string]interface{}{
  315. "ok": true,
  316. })
  317. }
  318. func Download(ctx *middleware.Context) {
  319. var (
  320. uri = ctx.Params("*")
  321. refName string
  322. ext string
  323. archivePath string
  324. archiveType git.ArchiveType
  325. )
  326. switch {
  327. case strings.HasSuffix(uri, ".zip"):
  328. ext = ".zip"
  329. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  330. archiveType = git.ZIP
  331. case strings.HasSuffix(uri, ".tar.gz"):
  332. ext = ".tar.gz"
  333. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  334. archiveType = git.TARGZ
  335. default:
  336. ctx.Error(404)
  337. return
  338. }
  339. refName = strings.TrimSuffix(uri, ext)
  340. if !com.IsDir(archivePath) {
  341. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  342. ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err)
  343. return
  344. }
  345. }
  346. // Get corresponding commit.
  347. var (
  348. commit *git.Commit
  349. err error
  350. )
  351. gitRepo := ctx.Repo.GitRepo
  352. if gitRepo.IsBranchExist(refName) {
  353. commit, err = gitRepo.GetCommitOfBranch(refName)
  354. if err != nil {
  355. ctx.Handle(500, "Download", err)
  356. return
  357. }
  358. } else if gitRepo.IsTagExist(refName) {
  359. commit, err = gitRepo.GetCommitOfTag(refName)
  360. if err != nil {
  361. ctx.Handle(500, "Download", err)
  362. return
  363. }
  364. } else if len(refName) == 40 {
  365. commit, err = gitRepo.GetCommit(refName)
  366. if err != nil {
  367. ctx.Handle(404, "Download", nil)
  368. return
  369. }
  370. } else {
  371. ctx.Error(404)
  372. return
  373. }
  374. archivePath = path.Join(archivePath, base.ShortSha(commit.Id.String())+ext)
  375. if !com.IsFile(archivePath) {
  376. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  377. ctx.Handle(500, "Download -> CreateArchive "+archivePath, err)
  378. return
  379. }
  380. }
  381. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(commit.Id.String())+ext)
  382. }