Browse Source

Web editor: support upload files

Unknwon 4 years ago
parent
commit
643142acab

+ 1 - 1
README.md

@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
3 3
 
4 4
 ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
5 5
 
6
-##### Current tip version: 0.9.94 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
6
+##### Current tip version: 0.9.95 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
7 7
 
8 8
 | Web | UI  | Preview  |
9 9
 |:-------------:|:-------:|:-------:|

+ 12 - 4
cmd/web.go

@@ -505,12 +505,20 @@ func runWeb(ctx *cli.Context) error {
505 505
 			m.Combo("/_new/*").Get(repo.NewFile).
506 506
 				Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost)
507 507
 			m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
508
-			m.Combo("/_upload/*").Get(repo.UploadFile).
509
-				Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
510 508
 			m.Combo("/_delete/*").Get(repo.DeleteFile).
511 509
 				Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
512
-			// m.Post("/upload-file", repo.UploadFileToServer)
513
-			// m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
510
+
511
+			m.Group("", func() {
512
+				m.Combo("/_upload/*").Get(repo.UploadFile).
513
+					Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
514
+				m.Post("/upload-file", repo.UploadFileToServer)
515
+				m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
516
+			}, func(ctx *context.Context) {
517
+				if !setting.Repository.Upload.Enabled {
518
+					ctx.Handle(404, "", nil)
519
+					return
520
+				}
521
+			})
514 522
 		}, reqRepoWriter, context.RepoRef(), func(ctx *context.Context) {
515 523
 			if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
516 524
 				ctx.Handle(404, "", nil)

+ 4 - 4
conf/app.ini

@@ -38,10 +38,10 @@ ENABLED = true
38 38
 TEMP_PATH = data/tmp/uploads
39 39
 ; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type
40 40
 ALLOWED_TYPES =
41
-; Max size of each file in MB. Defaults to 32MB
42
-FILE_MAX_SIZE = 32
43
-; Max number of files per upload. Defaults to 10
44
-MAX_FILES = 10
41
+; Max size of each file in MB. Defaults to 3MB
42
+FILE_MAX_SIZE = 3
43
+; Max number of files per upload. Defaults to 5
44
+MAX_FILES = 5
45 45
 
46 46
 [ui]
47 47
 ; Number of repositories that are showed in one explore page

+ 4 - 4
conf/locale/locale_en-US.ini

@@ -427,6 +427,7 @@ file_permalink = Permalink
427 427
 file_too_large = This file is too large to be shown
428 428
 
429 429
 editor.new_file = New file
430
+editor.upload_file = Upload file
430 431
 editor.edit_file = Edit file
431 432
 editor.preview_changes = Preview Changes
432 433
 editor.cannot_edit_non_text_files = Cannot edit non-text files
@@ -459,10 +460,9 @@ editor.file_changed_while_editing = File content has been changed since you star
459 460
 editor.file_already_exists = A file with name '%s' already exists in this repository.
460 461
 editor.no_changes_to_show = There are no changes to show.
461 462
 editor.fail_to_update_file = Failed to update/create file '%s' with error: %v
462
-upload_files = Upload files
463
-upload_file = Upload file
464
-add_files_to_dir = Add files to %s
465
-add_subdir = Add subdirectory...
463
+editor.add_subdir = Add subdirectory...
464
+editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v
465
+editor.upload_files_to_dir = Upload files to '%s'
466 466
 
467 467
 commits.commits = Commits
468 468
 commits.search = Search commits

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
17 17
 	"github.com/gogits/gogs/modules/setting"
18 18
 )
19 19
 
20
-const APP_VER = "0.9.94.0830"
20
+const APP_VER = "0.9.95.0830"
21 21
 
22 22
 func init() {
23 23
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 3 - 5
models/error.go

@@ -652,10 +652,8 @@ func (err ErrTeamAlreadyExist) Error() string {
652 652
 //
653 653
 
654 654
 type ErrUploadNotExist struct {
655
-	ID     int64
656
-	UUID   string
657
-	UserID int64
658
-	RepoID int64
655
+	ID   int64
656
+	UUID string
659 657
 }
660 658
 
661 659
 func IsErrUploadNotExist(err error) bool {
@@ -664,5 +662,5 @@ func IsErrUploadNotExist(err error) bool {
664 662
 }
665 663
 
666 664
 func (err ErrUploadNotExist) Error() string {
667
-	return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s, user_id: %d, repo_id: %d]", err.ID, err.UUID, err.UserID, err.RepoID)
665
+	return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
668 666
 }

+ 5 - 10
models/issue.go

@@ -1685,11 +1685,12 @@ func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment,
1685 1685
 		Name: name,
1686 1686
 	}
1687 1687
 
1688
-	if err = os.MkdirAll(path.Dir(attach.LocalPath()), os.ModePerm); err != nil {
1688
+	localPath := attach.LocalPath()
1689
+	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
1689 1690
 		return nil, fmt.Errorf("MkdirAll: %v", err)
1690 1691
 	}
1691 1692
 
1692
-	fw, err := os.Create(attach.LocalPath())
1693
+	fw, err := os.Create(localPath)
1693 1694
 	if err != nil {
1694 1695
 		return nil, fmt.Errorf("Create: %v", err)
1695 1696
 	}
@@ -1701,17 +1702,11 @@ func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment,
1701 1702
 		return nil, fmt.Errorf("Copy: %v", err)
1702 1703
 	}
1703 1704
 
1704
-	sess := x.NewSession()
1705
-	defer sessionRelease(sess)
1706
-	if err := sess.Begin(); err != nil {
1707
-		return nil, err
1708
-	}
1709
-
1710
-	if _, err := sess.Insert(attach); err != nil {
1705
+	if _, err := x.Insert(attach); err != nil {
1711 1706
 		return nil, err
1712 1707
 	}
1713 1708
 
1714
-	return attach, sess.Commit()
1709
+	return attach, nil
1715 1710
 }
1716 1711
 
1717 1712
 func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {

+ 1 - 1
models/models.go

@@ -60,7 +60,7 @@ var (
60 60
 func init() {
61 61
 	tables = append(tables,
62 62
 		new(User), new(PublicKey), new(AccessToken),
63
-		new(Repository), new(DeployKey), new(Collaboration), new(Access),
63
+		new(Repository), new(DeployKey), new(Collaboration), new(Access), new(Upload),
64 64
 		new(Watch), new(Star), new(Follow), new(Action),
65 65
 		new(Issue), new(PullRequest), new(Comment), new(Attachment), new(IssueUser),
66 66
 		new(Label), new(IssueLabel), new(Milestone),

+ 3 - 3
models/pull.go

@@ -339,9 +339,6 @@ var patchConflicts = []string{
339 339
 // testPatch checks if patch can be merged to base repository without conflit.
340 340
 // FIXME: make a mechanism to clean up stable local copies.
341 341
 func (pr *PullRequest) testPatch() (err error) {
342
-	repoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID))
343
-	defer repoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID))
344
-
345 342
 	if pr.BaseRepo == nil {
346 343
 		pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
347 344
 		if err != nil {
@@ -360,6 +357,9 @@ func (pr *PullRequest) testPatch() (err error) {
360 357
 		return nil
361 358
 	}
362 359
 
360
+	repoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID))
361
+	defer repoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID))
362
+
363 363
 	log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
364 364
 
365 365
 	if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {

+ 0 - 194
models/repo.go

@@ -9,9 +9,7 @@ import (
9 9
 	"errors"
10 10
 	"fmt"
11 11
 	"html/template"
12
-	"io"
13 12
 	"io/ioutil"
14
-	"mime/multipart"
15 13
 	"os"
16 14
 	"os/exec"
17 15
 	"path"
@@ -29,7 +27,6 @@ import (
29 27
 
30 28
 	git "github.com/gogits/git-module"
31 29
 	api "github.com/gogits/go-gogs-client"
32
-	gouuid "github.com/satori/go.uuid"
33 30
 
34 31
 	"github.com/gogits/gogs/modules/bindata"
35 32
 	"github.com/gogits/gogs/modules/log"
@@ -2272,197 +2269,6 @@ func (repo *Repository) GetForks() ([]*Repository, error) {
2272 2269
 	return forks, x.Find(&forks, &Repository{ForkID: repo.ID})
2273 2270
 }
2274 2271
 
2275
-//  ____ ___        .__                    .___ ___________.___.__
2276
-// |    |   \______ |  |   _________     __| _/ \_   _____/|   |  |   ____   ______
2277
-// |    |   /\____ \|  |  /  _ \__  \   / __ |   |    __)  |   |  | _/ __ \ /  ___/
2278
-// |    |  / |  |_> >  |_(  <_> ) __ \_/ /_/ |   |     \   |   |  |_\  ___/ \___ \
2279
-// |______/  |   __/|____/\____(____  /\____ |   \___  /   |___|____/\___  >____  >
2280
-//           |__|                   \/      \/       \/                  \/     \/
2281
-//
2282
-
2283
-// uploadRepoFiles uploads new files to repository.
2284
-func (repo *Repository) UploadRepoFiles(doer *User, oldBranchName, branchName, treePath, message string, uuids []string) (err error) {
2285
-	repoWorkingPool.CheckIn(com.ToStr(repo.ID))
2286
-	defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
2287
-
2288
-	localPath := repo.LocalCopyPath()
2289
-
2290
-	if err = discardLocalRepoBranchChanges(localPath, oldBranchName); err != nil {
2291
-		return fmt.Errorf("discardLocalRepoChanges: %v", err)
2292
-	} else if err = repo.UpdateLocalCopyBranch(oldBranchName); err != nil {
2293
-		return fmt.Errorf("UpdateLocalCopyBranch: %v", err)
2294
-	}
2295
-
2296
-	if oldBranchName != branchName {
2297
-		repo.CheckoutNewBranch(oldBranchName, branchName)
2298
-	}
2299
-
2300
-	dirPath := path.Join(localPath, treePath)
2301
-	os.MkdirAll(dirPath, os.ModePerm)
2302
-
2303
-	// Copy uploaded files into repository.
2304
-	for _, uuid := range uuids {
2305
-		upload, err := getUpload(uuid, doer.ID, repo.ID)
2306
-		if err != nil {
2307
-			if IsErrUploadNotExist(err) {
2308
-				continue
2309
-			}
2310
-			return fmt.Errorf("getUpload[%s]: %v", uuid, err)
2311
-		}
2312
-		uuidPath := upload.LocalPath()
2313
-		filePath := dirPath + "/" + upload.Name
2314
-		if err := os.Rename(uuidPath, filePath); err != nil {
2315
-			DeleteUpload(upload, true)
2316
-			return fmt.Errorf("Rename[%s -> %s]: %v", uuidPath, filePath, err)
2317
-		}
2318
-		DeleteUpload(upload, false) // false because we have moved the file
2319
-	}
2320
-
2321
-	if len(message) == 0 {
2322
-		message = "Add files to '" + treePath + "'"
2323
-	}
2324
-
2325
-	if err = git.AddChanges(localPath, true); err != nil {
2326
-		return fmt.Errorf("AddChanges: %v", err)
2327
-	} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
2328
-		Committer: doer.NewGitSig(),
2329
-		Message:   message,
2330
-	}); err != nil {
2331
-		return fmt.Errorf("CommitChanges: %v", err)
2332
-	} else if err = git.Push(localPath, "origin", branchName); err != nil {
2333
-		return fmt.Errorf("Push: %v", err)
2334
-	}
2335
-
2336
-	return nil
2337
-}
2338
-
2339
-// Upload represent a uploaded file to a repo to be deleted when moved
2340
-type Upload struct {
2341
-	ID          int64  `xorm:"pk autoincr"`
2342
-	UUID        string `xorm:"uuid UNIQUE"`
2343
-	UID         int64  `xorm:"INDEX"`
2344
-	RepoID      int64  `xorm:"INDEX"`
2345
-	Name        string
2346
-	Created     time.Time `xorm:"-"`
2347
-	CreatedUnix int64
2348
-}
2349
-
2350
-func (u *Upload) BeforeInsert() {
2351
-	u.CreatedUnix = time.Now().UTC().Unix()
2352
-}
2353
-
2354
-func (u *Upload) AfterSet(colName string, _ xorm.Cell) {
2355
-	switch colName {
2356
-	case "created_unix":
2357
-		u.Created = time.Unix(u.CreatedUnix, 0).Local()
2358
-	}
2359
-}
2360
-
2361
-// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
2362
-func UploadLocalPath(uuid string) string {
2363
-	return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
2364
-}
2365
-
2366
-// LocalPath returns where uploads are temporarily stored in local file system.
2367
-func (upload *Upload) LocalPath() string {
2368
-	return UploadLocalPath(upload.UUID)
2369
-}
2370
-
2371
-// NewUpload creates a new upload object.
2372
-func NewUpload(name string, buf []byte, file multipart.File, userId, repoId int64) (_ *Upload, err error) {
2373
-	up := &Upload{
2374
-		UUID:   gouuid.NewV4().String(),
2375
-		Name:   name,
2376
-		UID:    userId,
2377
-		RepoID: repoId,
2378
-	}
2379
-
2380
-	if err = os.MkdirAll(path.Dir(up.LocalPath()), os.ModePerm); err != nil {
2381
-		return nil, fmt.Errorf("MkdirAll: %v", err)
2382
-	}
2383
-
2384
-	fw, err := os.Create(up.LocalPath())
2385
-	if err != nil {
2386
-		return nil, fmt.Errorf("Create: %v", err)
2387
-	}
2388
-	defer fw.Close()
2389
-
2390
-	if _, err = fw.Write(buf); err != nil {
2391
-		return nil, fmt.Errorf("Write: %v", err)
2392
-	} else if _, err = io.Copy(fw, file); err != nil {
2393
-		return nil, fmt.Errorf("Copy: %v", err)
2394
-	}
2395
-
2396
-	sess := x.NewSession()
2397
-	defer sessionRelease(sess)
2398
-	if err := sess.Begin(); err != nil {
2399
-		return nil, err
2400
-	}
2401
-	if _, err := sess.Insert(up); err != nil {
2402
-		return nil, err
2403
-	}
2404
-
2405
-	return up, sess.Commit()
2406
-}
2407
-
2408
-// RemoveUpload removes the file by UUID
2409
-func RemoveUpload(uuid string, userId, repoId int64) (err error) {
2410
-	sess := x.NewSession()
2411
-	defer sessionRelease(sess)
2412
-	if err := sess.Begin(); err != nil {
2413
-		return err
2414
-	}
2415
-	upload, err := getUpload(uuid, userId, repoId)
2416
-	if err != nil {
2417
-		return fmt.Errorf("getUpload[%s]: %v", uuid, err)
2418
-	}
2419
-
2420
-	if err := DeleteUpload(upload, true); err != nil {
2421
-		return fmt.Errorf("DeleteUpload[%s]: %v", uuid, err)
2422
-	}
2423
-
2424
-	return nil
2425
-}
2426
-
2427
-func getUpload(uuid string, userID, repoID int64) (*Upload, error) {
2428
-	up := &Upload{UUID: uuid, UID: userID, RepoID: repoID}
2429
-	has, err := x.Get(up)
2430
-	if err != nil {
2431
-		return nil, err
2432
-	} else if !has {
2433
-		return nil, ErrUploadNotExist{0, uuid, userID, repoID}
2434
-	}
2435
-	return up, nil
2436
-}
2437
-
2438
-// GetUpload returns Upload by given UUID.
2439
-func GetUpload(uuid string, userId, repoId int64) (*Upload, error) {
2440
-	return getUpload(uuid, userId, repoId)
2441
-}
2442
-
2443
-// DeleteUpload deletes the given upload
2444
-func DeleteUpload(u *Upload, remove bool) error {
2445
-	_, err := DeleteUploads([]*Upload{u}, remove)
2446
-	return err
2447
-}
2448
-
2449
-// DeleteUploads deletes the given uploads
2450
-func DeleteUploads(uploads []*Upload, remove bool) (int, error) {
2451
-	for i, u := range uploads {
2452
-		if remove {
2453
-			if err := os.Remove(u.LocalPath()); err != nil {
2454
-				return i, err
2455
-			}
2456
-		}
2457
-
2458
-		if _, err := x.Delete(u); err != nil {
2459
-			return i, err
2460
-		}
2461
-	}
2462
-
2463
-	return len(uploads), nil
2464
-}
2465
-
2466 2272
 // __________                             .__
2467 2273
 // \______   \____________    ____   ____ |  |__
2468 2274
 //  |    |  _/\_  __ \__  \  /    \_/ ___\|  |  \

+ 227 - 0
models/repo_editor.go

@@ -6,7 +6,9 @@ package models
6 6
 
7 7
 import (
8 8
 	"fmt"
9
+	"io"
9 10
 	"io/ioutil"
11
+	"mime/multipart"
10 12
 	"os"
11 13
 	"os/exec"
12 14
 	"path"
@@ -14,6 +16,7 @@ import (
14 16
 	"time"
15 17
 
16 18
 	"github.com/Unknwon/com"
19
+	gouuid "github.com/satori/go.uuid"
17 20
 
18 21
 	git "github.com/gogits/git-module"
19 22
 
@@ -291,3 +294,227 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
291 294
 
292 295
 	return nil
293 296
 }
297
+
298
+//  ____ ___        .__                    .___ ___________.___.__
299
+// |    |   \______ |  |   _________     __| _/ \_   _____/|   |  |   ____   ______
300
+// |    |   /\____ \|  |  /  _ \__  \   / __ |   |    __)  |   |  | _/ __ \ /  ___/
301
+// |    |  / |  |_> >  |_(  <_> ) __ \_/ /_/ |   |     \   |   |  |_\  ___/ \___ \
302
+// |______/  |   __/|____/\____(____  /\____ |   \___  /   |___|____/\___  >____  >
303
+//           |__|                   \/      \/       \/                  \/     \/
304
+//
305
+
306
+// Upload represent a uploaded file to a repo to be deleted when moved
307
+type Upload struct {
308
+	ID   int64  `xorm:"pk autoincr"`
309
+	UUID string `xorm:"uuid UNIQUE"`
310
+	Name string
311
+}
312
+
313
+// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
314
+func UploadLocalPath(uuid string) string {
315
+	return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
316
+}
317
+
318
+// LocalPath returns where uploads are temporarily stored in local file system.
319
+func (upload *Upload) LocalPath() string {
320
+	return UploadLocalPath(upload.UUID)
321
+}
322
+
323
+// NewUpload creates a new upload object.
324
+func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err error) {
325
+	upload := &Upload{
326
+		UUID: gouuid.NewV4().String(),
327
+		Name: name,
328
+	}
329
+
330
+	localPath := upload.LocalPath()
331
+	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
332
+		return nil, fmt.Errorf("MkdirAll: %v", err)
333
+	}
334
+
335
+	fw, err := os.Create(localPath)
336
+	if err != nil {
337
+		return nil, fmt.Errorf("Create: %v", err)
338
+	}
339
+	defer fw.Close()
340
+
341
+	if _, err = fw.Write(buf); err != nil {
342
+		return nil, fmt.Errorf("Write: %v", err)
343
+	} else if _, err = io.Copy(fw, file); err != nil {
344
+		return nil, fmt.Errorf("Copy: %v", err)
345
+	}
346
+
347
+	if _, err := x.Insert(upload); err != nil {
348
+		return nil, err
349
+	}
350
+
351
+	return upload, nil
352
+}
353
+
354
+func GetUploadByUUID(uuid string) (*Upload, error) {
355
+	upload := &Upload{UUID: uuid}
356
+	has, err := x.Get(upload)
357
+	if err != nil {
358
+		return nil, err
359
+	} else if !has {
360
+		return nil, ErrUploadNotExist{0, uuid}
361
+	}
362
+	return upload, nil
363
+}
364
+
365
+func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
366
+	if len(uuids) == 0 {
367
+		return []*Upload{}, nil
368
+	}
369
+
370
+	// Silently drop invalid uuids.
371
+	uploads := make([]*Upload, 0, len(uuids))
372
+	return uploads, x.In("uuid", uuids).Find(&uploads)
373
+}
374
+
375
+func DeleteUploads(uploads ...*Upload) (err error) {
376
+	if len(uploads) == 0 {
377
+		return nil
378
+	}
379
+
380
+	sess := x.NewSession()
381
+	defer sessionRelease(sess)
382
+	if err = sess.Begin(); err != nil {
383
+		return err
384
+	}
385
+
386
+	ids := make([]int64, len(uploads))
387
+	for i := 0; i < len(uploads); i++ {
388
+		ids[i] = uploads[i].ID
389
+	}
390
+	if _, err = sess.In("id", ids).Delete(new(Upload)); err != nil {
391
+		return fmt.Errorf("delete uploads: %v", err)
392
+	}
393
+
394
+	for _, upload := range uploads {
395
+		localPath := upload.LocalPath()
396
+		if !com.IsFile(localPath) {
397
+			continue
398
+		}
399
+
400
+		if err := os.Remove(localPath); err != nil {
401
+			return fmt.Errorf("remove upload: %v", err)
402
+		}
403
+	}
404
+
405
+	return sess.Commit()
406
+}
407
+
408
+func DeleteUpload(u *Upload) error {
409
+	return DeleteUploads(u)
410
+}
411
+
412
+func DeleteUploadByUUID(uuid string) error {
413
+	upload, err := GetUploadByUUID(uuid)
414
+	if err != nil {
415
+		if IsErrUploadNotExist(err) {
416
+			return nil
417
+		}
418
+		return fmt.Errorf("GetUploadByUUID: %v", err)
419
+	}
420
+
421
+	if err := DeleteUpload(upload); err != nil {
422
+		return fmt.Errorf("DeleteUpload: %v", err)
423
+	}
424
+
425
+	return nil
426
+}
427
+
428
+type UploadRepoFileOptions struct {
429
+	LastCommitID string
430
+	OldBranch    string
431
+	NewBranch    string
432
+	TreePath     string
433
+	Message      string
434
+	Files        []string // In UUID format.
435
+}
436
+
437
+func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) (err error) {
438
+	if len(opts.Files) == 0 {
439
+		return nil
440
+	}
441
+
442
+	uploads, err := GetUploadsByUUIDs(opts.Files)
443
+	if err != nil {
444
+		return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %v", opts.Files, err)
445
+	}
446
+
447
+	repoWorkingPool.CheckIn(com.ToStr(repo.ID))
448
+	defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
449
+
450
+	if err = repo.DiscardLocalRepoBranchChanges(opts.OldBranch); err != nil {
451
+		return fmt.Errorf("DiscardLocalRepoBranchChanges [branch: %s]: %v", opts.OldBranch, err)
452
+	} else if err = repo.UpdateLocalCopyBranch(opts.OldBranch); err != nil {
453
+		return fmt.Errorf("UpdateLocalCopyBranch [branch: %s]: %v", opts.OldBranch, err)
454
+	}
455
+
456
+	if opts.OldBranch != opts.NewBranch {
457
+		if err = repo.CheckoutNewBranch(opts.OldBranch, opts.NewBranch); err != nil {
458
+			return fmt.Errorf("CheckoutNewBranch [old_branch: %s, new_branch: %s]: %v", opts.OldBranch, opts.NewBranch, err)
459
+		}
460
+	}
461
+
462
+	localPath := repo.LocalCopyPath()
463
+	dirPath := path.Join(localPath, opts.TreePath)
464
+	os.MkdirAll(dirPath, os.ModePerm)
465
+
466
+	// Copy uploaded files into repository.
467
+	for _, upload := range uploads {
468
+		tmpPath := upload.LocalPath()
469
+		targetPath := path.Join(dirPath, upload.Name)
470
+		if !com.IsFile(tmpPath) {
471
+			continue
472
+		}
473
+
474
+		if err = com.Copy(tmpPath, targetPath); err != nil {
475
+			return fmt.Errorf("Copy: %v", err)
476
+		}
477
+	}
478
+
479
+	if err = git.AddChanges(localPath, true); err != nil {
480
+		return fmt.Errorf("git add --all: %v", err)
481
+	} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
482
+		Committer: doer.NewGitSig(),
483
+		Message:   opts.Message,
484
+	}); err != nil {
485
+		return fmt.Errorf("CommitChanges: %v", err)
486
+	} else if err = git.Push(localPath, "origin", opts.NewBranch); err != nil {
487
+		return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
488
+	}
489
+
490
+	gitRepo, err := git.OpenRepository(repo.RepoPath())
491
+	if err != nil {
492
+		log.Error(4, "OpenRepository: %v", err)
493
+		return nil
494
+	}
495
+	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
496
+	if err != nil {
497
+		log.Error(4, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
498
+		return nil
499
+	}
500
+
501
+	// Simulate push event.
502
+	pushCommits := &PushCommits{
503
+		Len:     1,
504
+		Commits: []*PushCommit{CommitToPushCommit(commit)},
505
+	}
506
+	if err := CommitRepoAction(CommitRepoActionOptions{
507
+		PusherName:  doer.Name,
508
+		RepoOwnerID: repo.MustOwner().ID,
509
+		RepoName:    repo.Name,
510
+		RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
511
+		OldCommitID: opts.LastCommitID,
512
+		NewCommitID: commit.ID.String(),
513
+		Commits:     pushCommits,
514
+	}); err != nil {
515
+		log.Error(4, "CommitRepoAction: %v", err)
516
+		return nil
517
+	}
518
+
519
+	return DeleteUploads(uploads...)
520
+}

+ 1 - 1
modules/auth/repo_form.go

@@ -316,7 +316,7 @@ func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors
316 316
 //
317 317
 
318 318
 type UploadRepoFileForm struct {
319
-	TreeName      string `binding:MaxSize(500)"`
319
+	TreePath      string `binding:MaxSize(500)"`
320 320
 	CommitSummary string `binding:"MaxSize(100)`
321 321
 	CommitMessage string
322 322
 	CommitChoice  string `binding:"Required;MaxSize(50)"`

+ 1 - 0
modules/template/template.go

@@ -86,6 +86,7 @@ func NewFuncMap() []template.FuncMap {
86 86
 			}
87 87
 			return str[start:end]
88 88
 		},
89
+		"EllipsisString":    base.EllipsisString,
89 90
 		"DiffTypeToStr":     DiffTypeToStr,
90 91
 		"DiffLineTypeToStr": DiffLineTypeToStr,
91 92
 		"Sha1":              Sha1,

+ 4 - 4
public/css/gogs.css

@@ -1198,8 +1198,8 @@ footer .ui.language .menu {
1198 1198
 }
1199 1199
 .repository #clone-panel {
1200 1200
   margin-top: -8px;
1201
-  width: 100%;
1202
-  padding-left: 20px;
1201
+  margin-left: 5px;
1202
+  width: 350px;
1203 1203
 }
1204 1204
 .repository #clone-panel input {
1205 1205
   border-radius: 0;
@@ -2270,13 +2270,13 @@ footer .ui.language .menu {
2270 2270
 .page.buttons {
2271 2271
   padding-top: 15px;
2272 2272
 }
2273
-.ui.comments .dropzone {
2273
+.ui.form .dropzone {
2274 2274
   width: 100%;
2275 2275
   margin-bottom: 10px;
2276 2276
   border: 2px dashed #0087F7;
2277 2277
   box-shadow: none!important;
2278 2278
 }
2279
-.ui.comments .dropzone .dz-error-message {
2279
+.ui.form .dropzone .dz-error-message {
2280 2280
   top: 140px;
2281 2281
 }
2282 2282
 .settings .content {

+ 3 - 3
public/less/_repository.less

@@ -126,8 +126,8 @@
126 126
 
127 127
 	#clone-panel {
128 128
 		margin-top: -8px;
129
-		width: 100%;
130
-		padding-left: 20px;
129
+		margin-left: 5px;
130
+		width: 350px;
131 131
 
132 132
 		input {
133 133
 			border-radius: 0;
@@ -1303,7 +1303,7 @@
1303 1303
 	padding-top: 15px;
1304 1304
 }
1305 1305
 
1306
-.ui.comments {
1306
+.ui.form {
1307 1307
 	.dropzone {
1308 1308
 		width: 100%;
1309 1309
 		margin-bottom: 10px;

+ 183 - 16
routers/repo/editor.go

@@ -5,7 +5,9 @@
5 5
 package repo
6 6
 
7 7
 import (
8
+	"fmt"
8 9
 	"io/ioutil"
10
+	"net/http"
9 11
 	"path"
10 12
 	"strings"
11 13
 
@@ -23,6 +25,7 @@ const (
23 25
 	EDIT_FILE         base.TplName = "repo/editor/edit"
24 26
 	EDIT_DIFF_PREVIEW base.TplName = "repo/editor/diff_preview"
25 27
 	DELETE_FILE       base.TplName = "repo/editor/delete"
28
+	UPLOAD_FILE       base.TplName = "repo/editor/upload"
26 29
 )
27 30
 
28 31
 func editFile(ctx *context.Context, isNewFile bool) {
@@ -31,8 +34,6 @@ func editFile(ctx *context.Context, isNewFile bool) {
31 34
 	ctx.Data["RequireHighlightJS"] = true
32 35
 	ctx.Data["RequireSimpleMDE"] = true
33 36
 
34
-	branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
35
-
36 37
 	var treeNames []string
37 38
 	if len(ctx.Repo.TreePath) > 0 {
38 39
 		treeNames = strings.Split(ctx.Repo.TreePath, "/")
@@ -41,11 +42,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
41 42
 	if !isNewFile {
42 43
 		entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
43 44
 		if err != nil {
44
-			if git.IsErrNotExist(err) {
45
-				ctx.Handle(404, "GetTreeEntryByPath", err)
46
-			} else {
47
-				ctx.Handle(500, "GetTreeEntryByPath", err)
48
-			}
45
+			ctx.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err)
49 46
 			return
50 47
 		}
51 48
 
@@ -91,9 +88,8 @@ func editFile(ctx *context.Context, isNewFile bool) {
91 88
 		treeNames = append(treeNames, "") // Append empty string to allow user name the new file.
92 89
 	}
93 90
 
94
-	ctx.Data["TreePath"] = ctx.Repo.TreePath
95 91
 	ctx.Data["TreeNames"] = treeNames
96
-	ctx.Data["BranchLink"] = branchLink
92
+	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
97 93
 	ctx.Data["commit_summary"] = ""
98 94
 	ctx.Data["commit_message"] = ""
99 95
 	ctx.Data["commit_choice"] = "direct"
@@ -122,7 +118,6 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
122 118
 
123 119
 	oldBranchName := ctx.Repo.BranchName
124 120
 	branchName := oldBranchName
125
-	branchLink := ctx.Repo.RepoLink + "/src/" + branchName
126 121
 	oldTreePath := ctx.Repo.TreePath
127 122
 	lastCommit := form.LastCommit
128 123
 	form.LastCommit = ctx.Repo.Commit.ID.String()
@@ -140,7 +135,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
140 135
 
141 136
 	ctx.Data["TreePath"] = form.TreePath
142 137
 	ctx.Data["TreeNames"] = treeNames
143
-	ctx.Data["BranchLink"] = branchLink
138
+	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
144 139
 	ctx.Data["FileContent"] = form.Content
145 140
 	ctx.Data["commit_summary"] = form.CommitSummary
146 141
 	ctx.Data["commit_message"] = form.CommitMessage
@@ -180,7 +175,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
180 175
 				break
181 176
 			}
182 177
 
183
-			ctx.Handle(500, "GetTreeEntryByPath", err)
178
+			ctx.Handle(500, "Repo.Commit.GetTreeEntryByPath", err)
184 179
 			return
185 180
 		}
186 181
 		if index != len(treeNames)-1 {
@@ -326,7 +321,6 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
326 321
 
327 322
 	oldBranchName := ctx.Repo.BranchName
328 323
 	branchName := oldBranchName
329
-	treePath := ctx.Repo.TreePath
330 324
 
331 325
 	if form.CommitChoice == "commit-to-new-branch" {
332 326
 		branchName = form.NewBranchName
@@ -351,7 +345,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
351 345
 
352 346
 	message := strings.TrimSpace(form.CommitSummary)
353 347
 	if len(message) == 0 {
354
-		message = ctx.Tr("repo.editor.delete", treePath)
348
+		message = ctx.Tr("repo.editor.delete", ctx.Repo.TreePath)
355 349
 	}
356 350
 
357 351
 	form.CommitMessage = strings.TrimSpace(form.CommitMessage)
@@ -363,13 +357,186 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
363 357
 		LastCommitID: ctx.Repo.CommitID,
364 358
 		OldBranch:    oldBranchName,
365 359
 		NewBranch:    branchName,
366
-		TreePath:     treePath,
360
+		TreePath:     ctx.Repo.TreePath,
367 361
 		Message:      message,
368 362
 	}); err != nil {
369 363
 		ctx.Handle(500, "DeleteRepoFile", err)
370 364
 		return
371 365
 	}
372 366
 
373
-	ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", treePath))
367
+	ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
374 368
 	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName)
375 369
 }
370
+
371
+func renderUploadSettings(ctx *context.Context) {
372
+	ctx.Data["RequireDropzone"] = true
373
+	ctx.Data["UploadAllowedTypes"] = strings.Join(setting.Repository.Upload.AllowedTypes, ",")
374
+	ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize
375
+	ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles
376
+}
377
+
378
+func UploadFile(ctx *context.Context) {
379
+	ctx.Data["PageIsUpload"] = true
380
+	renderUploadSettings(ctx)
381
+
382
+	// We must at least have one element for user to input.
383
+	treeNames := []string{""}
384
+	if len(ctx.Repo.TreePath) > 0 {
385
+		treeNames = strings.Split(ctx.Repo.TreePath, "/")
386
+	}
387
+
388
+	ctx.Data["TreeNames"] = treeNames
389
+	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
390
+	ctx.Data["commit_summary"] = ""
391
+	ctx.Data["commit_message"] = ""
392
+	ctx.Data["commit_choice"] = "direct"
393
+	ctx.Data["new_branch_name"] = ""
394
+
395
+	ctx.HTML(200, UPLOAD_FILE)
396
+}
397
+
398
+func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
399
+	ctx.Data["PageIsUpload"] = true
400
+	renderUploadSettings(ctx)
401
+
402
+	oldBranchName := ctx.Repo.BranchName
403
+	branchName := oldBranchName
404
+
405
+	if form.CommitChoice == "commit-to-new-branch" {
406
+		branchName = form.NewBranchName
407
+	}
408
+
409
+	form.TreePath = strings.Trim(form.TreePath, " /")
410
+
411
+	// We must at least have one element for user to input.
412
+	treeNames := []string{""}
413
+	if len(form.TreePath) > 0 {
414
+		treeNames = strings.Split(form.TreePath, "/")
415
+	}
416
+
417
+	ctx.Data["TreePath"] = form.TreePath
418
+	ctx.Data["TreeNames"] = treeNames
419
+	ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
420
+	ctx.Data["commit_summary"] = form.CommitSummary
421
+	ctx.Data["commit_message"] = form.CommitMessage
422
+	ctx.Data["commit_choice"] = form.CommitChoice
423
+	ctx.Data["new_branch_name"] = branchName
424
+
425
+	if ctx.HasError() {
426
+		ctx.HTML(200, UPLOAD_FILE)
427
+		return
428
+	}
429
+
430
+	if oldBranchName != branchName {
431
+		if _, err := ctx.Repo.Repository.GetBranch(branchName); err == nil {
432
+			ctx.Data["Err_NewBranchName"] = true
433
+			ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), UPLOAD_FILE, &form)
434
+			return
435
+		}
436
+	}
437
+
438
+	var newTreePath string
439
+	for _, part := range treeNames {
440
+		newTreePath = path.Join(newTreePath, part)
441
+		entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
442
+		if err != nil {
443
+			if git.IsErrNotExist(err) {
444
+				// Means there is no item with that name, so we're good
445
+				break
446
+			}
447
+
448
+			ctx.Handle(500, "Repo.Commit.GetTreeEntryByPath", err)
449
+			return
450
+		}
451
+
452
+		// User can only upload files to a directory.
453
+		if !entry.IsDir() {
454
+			ctx.Data["Err_TreePath"] = true
455
+			ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &form)
456
+			return
457
+		}
458
+	}
459
+
460
+	message := strings.TrimSpace(form.CommitSummary)
461
+	if len(message) == 0 {
462
+		message = ctx.Tr("repo.editor.upload_files_to_dir", form.TreePath)
463
+	}
464
+
465
+	form.CommitMessage = strings.TrimSpace(form.CommitMessage)
466
+	if len(form.CommitMessage) > 0 {
467
+		message += "\n\n" + form.CommitMessage
468
+	}
469
+
470
+	if err := ctx.Repo.Repository.UploadRepoFiles(ctx.User, models.UploadRepoFileOptions{
471
+		LastCommitID: ctx.Repo.CommitID,
472
+		OldBranch:    oldBranchName,
473
+		NewBranch:    branchName,
474
+		TreePath:     form.TreePath,
475
+		Message:      message,
476
+		Files:        form.Files,
477
+	}); err != nil {
478
+		ctx.Data["Err_TreePath"] = true
479
+		ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), UPLOAD_FILE, &form)
480
+		return
481
+	}
482
+
483
+	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + form.TreePath)
484
+}
485
+
486
+func UploadFileToServer(ctx *context.Context) {
487
+	file, header, err := ctx.Req.FormFile("file")
488
+	if err != nil {
489
+		ctx.Error(500, fmt.Sprintf("FormFile: %v", err))
490
+		return
491
+	}
492
+	defer file.Close()
493
+
494
+	buf := make([]byte, 1024)
495
+	n, _ := file.Read(buf)
496
+	if n > 0 {
497
+		buf = buf[:n]
498
+	}
499
+	fileType := http.DetectContentType(buf)
500
+
501
+	if len(setting.Repository.Upload.AllowedTypes) > 0 {
502
+		allowed := false
503
+		for _, t := range setting.Repository.Upload.AllowedTypes {
504
+			t := strings.Trim(t, " ")
505
+			if t == "*/*" || t == fileType {
506
+				allowed = true
507
+				break
508
+			}
509
+		}
510
+
511
+		if !allowed {
512
+			ctx.Error(400, ErrFileTypeForbidden.Error())
513
+			return
514
+		}
515
+	}
516
+
517
+	upload, err := models.NewUpload(header.Filename, buf, file)
518
+	if err != nil {
519
+		ctx.Error(500, fmt.Sprintf("NewUpload: %v", err))
520
+		return
521
+	}
522
+
523
+	log.Trace("New file uploaded: %s", upload.UUID)
524
+	ctx.JSON(200, map[string]string{
525
+		"uuid": upload.UUID,
526
+	})
527
+}
528
+
529
+func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFileForm) {
530
+	if len(form.File) == 0 {
531
+		ctx.Status(204)
532
+		return
533
+	}
534
+
535
+	if err := models.DeleteUploadByUUID(form.File); err != nil {
536
+		ctx.Error(500, fmt.Sprintf("DeleteUploadByUUID: %v", err))
537
+		return
538
+	}
539
+
540
+	log.Trace("Upload file removed: %s", form.File)
541
+	ctx.Status(204)
542
+}

+ 1 - 1
routers/repo/issue.go

@@ -447,7 +447,6 @@ func UploadIssueAttachment(ctx *context.Context) {
447 447
 		return
448 448
 	}
449 449
 
450
-	allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",")
451 450
 	file, header, err := ctx.Req.FormFile("file")
452 451
 	if err != nil {
453 452
 		ctx.Error(500, fmt.Sprintf("FormFile: %v", err))
@@ -462,6 +461,7 @@ func UploadIssueAttachment(ctx *context.Context) {
462 461
 	}
463 462
 	fileType := http.DetectContentType(buf)
464 463
 
464
+	allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",")
465 465
 	allowed := false
466 466
 	for _, t := range allowedTypes {
467 467
 		t := strings.Trim(t, " ")

+ 0 - 253
routers/repo/upload.go

@@ -1,253 +0,0 @@
1
-// Copyright 2016 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
-
5
-package repo
6
-
7
-import (
8
-	"fmt"
9
-	"net/http"
10
-	"path"
11
-	"strings"
12
-
13
-	git "github.com/gogits/git-module"
14
-
15
-	"github.com/gogits/gogs/models"
16
-	"github.com/gogits/gogs/modules/auth"
17
-	"github.com/gogits/gogs/modules/base"
18
-	"github.com/gogits/gogs/modules/context"
19
-	"github.com/gogits/gogs/modules/log"
20
-	"github.com/gogits/gogs/modules/setting"
21
-)
22
-
23
-const (
24
-	UPLOAD base.TplName = "repo/upload"
25
-)
26
-
27
-func renderUploadSettings(ctx *context.Context) {
28
-	ctx.Data["RequireDropzone"] = true
29
-	ctx.Data["IsUploadEnabled"] = setting.Repository.Upload.Enabled
30
-	ctx.Data["UploadAllowedTypes"] = strings.Join(setting.Repository.Upload.AllowedTypes, ",")
31
-	ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize
32
-	ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles
33
-}
34
-
35
-func UploadFile(ctx *context.Context) {
36
-	ctx.Data["PageIsUpload"] = true
37
-
38
-	userName := ctx.Repo.Owner.Name
39
-	repoName := ctx.Repo.Repository.Name
40
-	branchName := ctx.Repo.BranchName
41
-	branchLink := ctx.Repo.RepoLink + "/src/" + branchName
42
-	treeName := ctx.Repo.TreePath
43
-
44
-	treeNames := []string{""}
45
-	if len(treeName) > 0 {
46
-		treeNames = strings.Split(treeName, "/")
47
-	}
48
-
49
-	ctx.Data["UserName"] = userName
50
-	ctx.Data["RepoName"] = repoName
51
-	ctx.Data["BranchName"] = branchName
52
-	ctx.Data["TreeName"] = treeName
53
-	ctx.Data["TreeNames"] = treeNames
54
-	ctx.Data["BranchLink"] = branchLink
55
-	ctx.Data["CommitSummary"] = ""
56
-	ctx.Data["CommitMessage"] = ""
57
-	ctx.Data["CommitChoice"] = "direct"
58
-	ctx.Data["NewBranchName"] = ""
59
-	ctx.Data["CommitDirectlyToThisBranch"] = ctx.Tr("repo.commit_directly_to_this_branch", "<strong class=\"branch-name\">"+branchName+"</strong>")
60
-	ctx.Data["CreateNewBranch"] = ctx.Tr("repo.create_new_branch", "<strong>"+ctx.Tr("repo.new_branch")+"</strong>")
61
-	renderUploadSettings(ctx)
62
-
63
-	ctx.HTML(200, UPLOAD)
64
-}
65
-
66
-func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
67
-	ctx.Data["PageIsUpload"] = true
68
-	renderUploadSettings(ctx)
69
-
70
-	userName := ctx.Repo.Owner.Name
71
-	repoName := ctx.Repo.Repository.Name
72
-	oldBranchName := ctx.Repo.BranchName
73
-	branchName := oldBranchName
74
-	branchLink := ctx.Repo.RepoLink + "/src/" + branchName
75
-	commitChoice := form.CommitChoice
76
-	files := form.Files
77
-
78
-	if commitChoice == "commit-to-new-branch" {
79
-		branchName = form.NewBranchName
80
-	}
81
-
82
-	treeName := form.TreeName
83
-	treeName = strings.Trim(treeName, " ")
84
-	treeName = strings.Trim(treeName, "/")
85
-
86
-	treeNames := []string{""}
87
-	if len(treeName) > 0 {
88
-		treeNames = strings.Split(treeName, "/")
89
-	}
90
-
91
-	ctx.Data["UserName"] = userName
92
-	ctx.Data["RepoName"] = repoName
93
-	ctx.Data["BranchName"] = branchName
94
-	ctx.Data["TreeName"] = treeName
95
-	ctx.Data["TreeNames"] = treeNames
96
-	ctx.Data["BranchLink"] = branchLink
97
-	ctx.Data["CommitSummary"] = form.CommitSummary
98
-	ctx.Data["CommitMessage"] = form.CommitMessage
99
-	ctx.Data["CommitChoice"] = commitChoice
100
-	ctx.Data["NewBranchName"] = branchName
101
-	ctx.Data["CommitDirectlyToThisBranch"] = ctx.Tr("repo.commit_directly_to_this_branch", "<strong class=\"branch-name\">"+oldBranchName+"</strong>")
102
-	ctx.Data["CreateNewBranch"] = ctx.Tr("repo.create_new_branch", "<strong>"+ctx.Tr("repo.new_branch")+"</strong>")
103
-
104
-	if ctx.HasError() {
105
-		ctx.HTML(200, UPLOAD)
106
-		return
107
-	}
108
-
109
-	if oldBranchName != branchName {
110
-		if _, err := ctx.Repo.Repository.GetBranch(branchName); err == nil {
111
-			ctx.Data["Err_Branchname"] = true
112
-			ctx.RenderWithErr(ctx.Tr("repo.branch_already_exists"), UPLOAD, &form)
113
-			log.Error(4, "%s: %s - %s", "BranchName", branchName, "Branch already exists")
114
-			return
115
-		}
116
-
117
-	}
118
-
119
-	treepath := ""
120
-	for _, part := range treeNames {
121
-		treepath = path.Join(treepath, part)
122
-		entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treepath)
123
-		if err != nil {
124
-			// Means there is no item with that name, so we're good
125
-			break
126
-		}
127
-		if !entry.IsDir() {
128
-			ctx.Data["Err_Filename"] = true
129
-			ctx.RenderWithErr(ctx.Tr("repo.directory_is_a_file"), UPLOAD, &form)
130
-			log.Error(4, "%s: %s - %s", "UploadFile", treeName, "Directory given is a file")
131
-			return
132
-		}
133
-	}
134
-
135
-	message := ""
136
-	if form.CommitSummary != "" {
137
-		message = strings.Trim(form.CommitSummary, " ")
138
-	} else {
139
-		message = ctx.Tr("repo.add_files_to_dir", "'"+treeName+"'")
140
-	}
141
-	if strings.Trim(form.CommitMessage, " ") != "" {
142
-		message += "\n\n" + strings.Trim(form.CommitMessage, " ")
143
-	}
144
-
145
-	if err := ctx.Repo.Repository.UploadRepoFiles(ctx.User, oldBranchName, branchName, treeName, message, files); err != nil {
146
-		ctx.Data["Err_Directory"] = true
147
-		ctx.RenderWithErr(ctx.Tr("repo.unable_to_upload_files"), UPLOAD, &form)
148
-		log.Error(4, "%s: %v", "UploadFile", err)
149
-		return
150
-	}
151
-
152
-	// Was successful, so now need to call models.CommitRepoAction() with the new commitID for webhooks and watchers
153
-	if branch, err := ctx.Repo.Repository.GetBranch(branchName); err != nil {
154
-		log.Error(4, "repo.Repository.GetBranch(%s): %v", branchName, err)
155
-	} else if commit, err := branch.GetCommit(); err != nil {
156
-		log.Error(4, "branch.GetCommit(): %v", err)
157
-	} else {
158
-		pc := &models.PushCommits{
159
-			Len:     1,
160
-			Commits: []*models.PushCommit{models.CommitToPushCommit(commit)},
161
-		}
162
-		oldCommitID := ctx.Repo.CommitID
163
-		newCommitID := commit.ID.String()
164
-		if branchName != oldBranchName {
165
-			oldCommitID = "0000000000000000000000000000000000000000" // New Branch so we use all 0s
166
-		}
167
-		if err := models.CommitRepoAction(models.CommitRepoActionOptions{
168
-			PusherName:  ctx.User.Name,
169
-			RepoOwnerID: ctx.Repo.Owner.ID,
170
-			RepoName:    ctx.Repo.Owner.Name,
171
-			RefFullName: git.BRANCH_PREFIX + branchName,
172
-			OldCommitID: oldCommitID,
173
-			NewCommitID: newCommitID,
174
-			Commits:     pc,
175
-		}); err != nil {
176
-			log.Error(4, "models.CommitRepoAction(branch = %s): %v", branchName, err)
177
-		}
178
-	}
179
-
180
-	ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + treeName)
181
-}
182
-
183
-func UploadFileToServer(ctx *context.Context) {
184
-	if !setting.Repository.Upload.Enabled {
185
-		ctx.Error(404, "upload is not enabled")
186
-		return
187
-	}
188
-
189
-	file, header, err := ctx.Req.FormFile("file")
190
-	if err != nil {
191
-		ctx.Error(500, fmt.Sprintf("FormFile: %v", err))
192
-		return
193
-	}
194
-	defer file.Close()
195
-
196
-	buf := make([]byte, 1024)
197
-	n, _ := file.Read(buf)
198
-	if n > 0 {
199
-		buf = buf[:n]
200
-	}
201
-	fileType := http.DetectContentType(buf)
202
-
203
-	if len(setting.Repository.Upload.AllowedTypes) > 0 {
204
-		allowed := false
205
-		for _, t := range setting.Repository.Upload.AllowedTypes {
206
-			t := strings.Trim(t, " ")
207
-			if t == "*/*" || t == fileType {
208
-				allowed = true
209
-				break
210
-			}
211
-		}
212
-
213
-		if !allowed {
214
-			ctx.Error(400, ErrFileTypeForbidden.Error())
215
-			return
216
-		}
217
-	}
218
-
219
-	up, err := models.NewUpload(header.Filename, buf, file, ctx.User.ID, ctx.Repo.Repository.ID)
220
-	if err != nil {
221
-		ctx.Error(500, fmt.Sprintf("NewUpload: %v", err))
222
-		return
223
-	}
224
-
225
-	log.Trace("New file uploaded: %s", up.UUID)
226
-	ctx.JSON(200, map[string]string{
227
-		"uuid": up.UUID,
228
-	})
229
-}
230
-
231
-func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFileForm) {
232
-	if !setting.Repository.Upload.Enabled {
233
-		ctx.Error(404, "upload is not enabled")
234
-		return
235
-	}
236
-
237
-	if len(form.File) == 0 {
238
-		ctx.Error(404, "invalid params")
239
-		return
240
-	}
241
-
242
-	uuid := form.File
243
-
244
-	if err := models.RemoveUpload(uuid, ctx.User.ID, ctx.Repo.Repository.ID); err != nil {
245
-		ctx.Error(500, fmt.Sprintf("RemoveUpload: %v", err))
246
-		return
247
-	}
248
-
249
-	log.Trace("Upload file removed: %s", uuid)
250
-	ctx.JSON(200, map[string]string{
251
-		"uuid": uuid,
252
-	})
253
-}

+ 2 - 5
routers/repo/view.go

@@ -113,10 +113,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
113 113
 	// Check permission to add or upload new file.
114 114
 	if ctx.Repo.IsWriter() && ctx.Repo.IsViewBranch {
115 115
 		ctx.Data["CanAddFile"] = true
116
-		// uploadFileLink := ctx.Repo.RepoLink + "/upload/" + branchName
117
-		// if setting.Repository.Upload.Enabled {
118
-		// 	ctx.Data["UploadFileLink"] = uploadFileLink + "/" +  ctx.Repo.TreePath
119
-		// }
116
+		ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled
120 117
 	}
121 118
 }
122 119
 
@@ -253,7 +250,7 @@ func Home(ctx *context.Context) {
253 250
 
254 251
 	ec, err := ctx.Repo.GetEditorconfig()
255 252
 	if err != nil && !git.IsErrNotExist(err) {
256
-		ctx.Handle(500, "ErrGettingEditorconfig", err)
253
+		ctx.Handle(500, "Repo.GetEditorconfig", err)
257 254
 		return
258 255
 	}
259 256
 	ctx.Data["Editorconfig"] = ec

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
1
-0.9.94.0830
1
+0.9.95.0830

+ 1 - 1
templates/repo/editor/commit_form.tmpl

@@ -3,7 +3,7 @@
3 3
 	<div class="commit-form">
4 4
 		<h3>{{.i18n.Tr "repo.editor.commit_changes"}}</h3>
5 5
 		<div class="field">
6
-			<input name="commit_summary" placeholder="{{if .PageIsDelete}}{{.i18n.Tr "repo.editor.delete" .TreePath}}{{else if .IsNewFile}}{{.i18n.Tr "repo.editor.add_tmpl" .TreePath}}{{else}}{{.i18n.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
6
+			<input name="commit_summary" placeholder="{{if .PageIsDelete}}{{.i18n.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{.i18n.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{.i18n.Tr "repo.editor.add_tmpl" .TreePath}}{{else}}{{.i18n.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
7 7
 		</div>
8 8
 		<div class="field">
9 9
 			<textarea name="commit_message" placeholder="{{.i18n.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea>

File diff suppressed because it is too large
+ 36 - 0
templates/repo/editor/upload.tmpl


+ 9 - 9
templates/repo/home.tmpl

@@ -18,36 +18,36 @@
18 18
 			{{template "repo/branch_dropdown" .}}
19 19
 			<div class="fitted item">
20 20
 				<div class="ui breadcrumb">
21
-					<a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchName}}">{{.Repository.Name}}</a>
21
+					<a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchName}}">{{EllipsisString .Repository.Name 25}}</a>
22 22
 					{{ $n := len .TreeNames}}
23 23
 					{{ $l := Subtract $n 1}}
24 24
 					{{range $i, $v := .TreeNames}}
25 25
 						<div class="divider"> / </div>
26 26
 						{{if eq $i $l}}
27
-							<span class="active section">{{$v}}</span>
27
+							<span class="active section">{{EllipsisString $v 15}}</span>
28 28
 						{{else}}
29 29
 							{{ $p := index $.Paths $i}}
30
-							<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}">{{$v}}</a></span>
30
+							<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}">{{EllipsisString $v 15}}</a></span>
31 31
 						{{end}}
32 32
 					{{end}}
33 33
 				</div>
34 34
 			</div>
35 35
 			<div class="right fitted item">
36 36
 				{{if .Repository.CanEnableEditor}}
37
-					<div id="file-buttons" class="ui tiny buttons">
37
+					<div id="file-buttons" class="ui tiny blue buttons">
38 38
 						{{if .CanAddFile}}
39 39
 							<a href="{{.RepoLink}}/_new/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button">
40 40
 								{{.i18n.Tr "repo.editor.new_file"}}
41 41
 							</a>
42 42
 						{{end}}
43
-						{{if .UploadFileLink}}
44
-							<!-- <a href="{{EscapePound .UploadFileLink}}" class="ui button nowrap">
45
-								<i class="upload icon"></i> {{.i18n.Tr "repo.upload_file"}}
46
-							</a> -->
43
+						{{if .CanUploadFile}}
44
+							<a href="{{.RepoLink}}/_upload/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button">
45
+								{{.i18n.Tr "repo.editor.upload_file"}}
46
+							</a>
47 47
 						{{end}}
48 48
 					</div>
49 49
 				{{end}}
50
-				
50
+
51 51
 				<!-- Only show colne panel in repository home page -->
52 52
 				{{if eq $n 0}}
53 53
 					<div class="ui action small input" id="clone-panel">

File diff suppressed because it is too large
+ 0 - 79
templates/repo/upload.tmpl