diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index e007c11d..3d298fe5 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -136,6 +136,8 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven {templateUrl: "/partials/error.html"}) $routeProvider.when("/not-found", {templateUrl: "/partials/not-found.html"}) + $routeProvider.when("/permission-denied", + {templateUrl: "/partials/permission-denied.html"}) $routeProvider.otherwise({redirectTo: '/not-found'}) $locationProvider.html5Mode(true) diff --git a/app/coffee/classes.coffee b/app/coffee/classes.coffee index 14ffc5ec..7e995c09 100644 --- a/app/coffee/classes.coffee +++ b/app/coffee/classes.coffee @@ -22,6 +22,16 @@ class TaigaBase class TaigaService extends TaigaBase class TaigaController extends TaigaBase + onInitialDataError: (xhr) => + if xhr + if xhr.status == 404 + @location.path(@navUrls.resolve("not-found")) + @location.replace() + else if xhr.status == 403 + @location.path(@navUrls.resolve("permission-denied")) + @location.replace() + + return @q.reject(xhr) @.taiga.Base = TaigaBase @.taiga.Service = TaigaService diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 849df141..3c660432 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -58,11 +58,7 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai promise.then => @appTitle.set("Membership - " + @scope.project.name) - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) @scope.$on "membersform:new:success", => @.loadMembers() diff --git a/app/coffee/modules/admin/project-profile.coffee b/app/coffee/modules/admin/project-profile.coffee index bfb6722d..3c1b3505 100644 --- a/app/coffee/modules/admin/project-profile.coffee +++ b/app/coffee/modules/admin/project-profile.coffee @@ -57,11 +57,7 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) promise.then => @appTitle.set("Project profile - " + @scope.sectionName + " - " + @scope.project.name) - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) @scope.$on "project:loaded", => @appTitle.set("Project profile - " + @scope.sectionName + " - " + @scope.project.name) diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index e86ee0b1..72351515 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -57,11 +57,7 @@ class ProjectValuesController extends mixOf(taiga.Controller, taiga.PageMixin) promise.then () => @appTitle.set("Project values - " + @scope.sectionName + " - " + @scope.project.name) - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) @scope.$on("admin:project-values:move", @.moveValue) diff --git a/app/coffee/modules/admin/roles.coffee b/app/coffee/modules/admin/roles.coffee index b3c64464..423a0ecb 100644 --- a/app/coffee/modules/admin/roles.coffee +++ b/app/coffee/modules/admin/roles.coffee @@ -58,11 +58,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil promise.then () => @appTitle.set("Roles - " + @scope.project.name) - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index 8ac10ce4..9dae3573 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -74,11 +74,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> @scope.$on "usform:bulk:success", => diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index 9a4a309f..d3dffe7f 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -46,6 +46,7 @@ urls = { "home": "/" "error": "/error" "not-found": "/not-found" + "permission-denied": "/permission-denied" "login": "/login" "forgot-password": "/forgot-password" diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index 7db92857..b526a337 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -62,11 +62,7 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @appTitle.set(@scope.issue.subject + " - " + @scope.project.name) # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 4ddd3a41..c005e041 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -74,11 +74,7 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) @scope.$on "issueform:new:success", => @analytics.trackEvent("issue", "create", "create issue on issues list", 1) diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 1446fb39..dda5460d 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -78,12 +78,7 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) - + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> @scope.$on "usform:new:success", => diff --git a/app/coffee/modules/projects/main.coffee b/app/coffee/modules/projects/main.coffee index 86b438f9..db64d8d2 100644 --- a/app/coffee/modules/projects/main.coffee +++ b/app/coffee/modules/projects/main.coffee @@ -53,11 +53,7 @@ class ProjectsController extends taiga.Controller @scope.$emit("projects:loaded") @tgLoader.pageLoaded() - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadInitialData: -> return @rs.projects.list().then (projects) => @@ -96,11 +92,7 @@ class ProjectController extends taiga.Controller promise.then () => @appTitle.set(@scope.project.name) - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadInitialData: -> # Resolve project slug diff --git a/app/coffee/modules/search.coffee b/app/coffee/modules/search.coffee index fa5b390e..e22c787d 100644 --- a/app/coffee/modules/search.coffee +++ b/app/coffee/modules/search.coffee @@ -55,11 +55,7 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin) promise.then () => @appTitle.set("Search") - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) # Search input watcher @scope.searchTerm = "" diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 8cd2dc37..bed2c3ba 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -66,11 +66,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> # TODO: Reload entire taskboard after create/edit tasks seems diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index 7592c34b..de3b715d 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -59,11 +59,7 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @appTitle.set(@scope.task.subject + " - " + @scope.project.name) tgLoader.pageLoaded() - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> @scope.$on "attachment:create", => diff --git a/app/coffee/modules/user-settings/change-password.coffee b/app/coffee/modules/user-settings/change-password.coffee index 3db6c237..54aeb0de 100644 --- a/app/coffee/modules/user-settings/change-password.coffee +++ b/app/coffee/modules/user-settings/change-password.coffee @@ -51,11 +51,7 @@ class UserChangePasswordController extends mixOf(taiga.Controller, taiga.PageMix promise = @.loadInitialData() - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => diff --git a/app/coffee/modules/user-settings/main.coffee b/app/coffee/modules/user-settings/main.coffee index 6137264f..dddf70f0 100644 --- a/app/coffee/modules/user-settings/main.coffee +++ b/app/coffee/modules/user-settings/main.coffee @@ -49,11 +49,7 @@ class UserSettingsController extends mixOf(taiga.Controller, taiga.PageMixin) promise = @.loadInitialData() - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => diff --git a/app/coffee/modules/user-settings/notifications.coffee b/app/coffee/modules/user-settings/notifications.coffee index b6e392f0..6af3c428 100644 --- a/app/coffee/modules/user-settings/notifications.coffee +++ b/app/coffee/modules/user-settings/notifications.coffee @@ -51,11 +51,7 @@ class UserNotificationsController extends mixOf(taiga.Controller, taiga.PageMixi promise = @.loadInitialData() - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => diff --git a/app/coffee/modules/userstories/detail.coffee b/app/coffee/modules/userstories/detail.coffee index a944ec43..f3845362 100644 --- a/app/coffee/modules/userstories/detail.coffee +++ b/app/coffee/modules/userstories/detail.coffee @@ -62,11 +62,7 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) initializeEventHandlers: -> @scope.$on "attachment:create", => diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index fb7a52ee..de58d10e 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -65,11 +65,7 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) tgLoader.pageLoaded() # On Error - promise.then null, (xhr) => - if xhr and xhr.status == 404 - @location.path(@navUrls.resolve("not-found")) - @location.replace() - return @q.reject(xhr) + promise.then null, @.onInitialDataError.bind(@) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => diff --git a/app/partials/permission-denied.jade b/app/partials/permission-denied.jade new file mode 100644 index 00000000..a855c2af --- /dev/null +++ b/app/partials/permission-denied.jade @@ -0,0 +1,7 @@ +div.error-main + div.error-container + object.logo-svg(type="image/svg+xml", data="/svg/logo.svg") + img(src="/images/logo.png", alt="TAIGA") + h1.logo Permission denied + p.error-text Error 403. + a(href="/", title="") Take me home