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.

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