Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/lib/route_filters/repository_owner_namespacing.rb
blob: 94f56d6eb0241587a8950ad43589a14b16da65fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# encoding: utf-8
#--
#   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#++
require "gitorious/reservations"
require 'routing_filter/base'

module RoutingFilter
  class RepositoryOwnerNamespacing < Base
    
    RESERVED_NAMES = Gitorious::Reservations.reserved_root_names
    CONTROLLER_NAMES = Gitorious::Reservations.controller_names + RESERVED_NAMES
    NAME_WITH_FORMAT_RE = /[a-z0-9_\-\.]+/i
    PREFIXES_TO_CONTROLLER = {
      "~" => "users",
      "+" => "teams",
      ""  => "projects",
    }
    PREFIXES_RE = Regexp.union(*PREFIXES_TO_CONTROLLER.keys)
    CONTROLLER_RE = Regexp.union(*PREFIXES_TO_CONTROLLER.invert.keys)
    
    # TODO: There's a special place in hell for this kinda logic; clean up
    
    def around_recognize(path, env, &block)
      if !reserved?(path)
         if path =~ /^\/(#{PREFIXES_RE})(#{NAME_WITH_FORMAT_RE})(\/.+)?/i
           controller = PREFIXES_TO_CONTROLLER[$1]
           name = $2
           rest = $3
           if rest && !reserved_action_name?(name, controller) && !reserved?(rest, controller) && repository_scope?(rest)
             # Handle repositories namespaced like ":user_or_team_id/:project_id/:repo_id"
             rest, project_or_repoish = rest.sub(/^\//, '').split("/", 2).reverse
             if !project_or_repoish.blank? && !rest.blank? && !reserved_action_name?(rest, "repositories") # got something that looks namespaced
               if reserved_action_name?(rest, controller) # we're looking for an action on repositories
                 path.replace "/#{controller}/#{name}/repositories/#{project_or_repoish}/#{rest}".chomp("/")
               else # We're in the /user_or_team/projectname/... scope
                 # We actually wanted another controller under repositories, not a repo:
                 if CONTROLLER_NAMES.include?(rest.split(".", 2).first.split("/")[0])
                   path.replace "/#{controller}/#{name}/repositories/#{project_or_repoish}/#{rest}".chomp("/")
                 else
                   path.replace "/#{controller}/#{name}/projects/#{project_or_repoish}/repositories/#{rest}".chomp("/")
                 end
               end
             else
               if project_or_repoish
                 path.replace "/#{controller}/#{name}/repositories/#{project_or_repoish}/#{rest}".chomp("/")
               else
                 path.replace "/#{controller}/#{name}/repositories/#{rest}".chomp("/")
               end
             end
           else
             path.replace "/#{controller}/#{name}#{rest}".chomp("/")
           end
         end
      end
      yield
      # returning yield(path, env) do |params|
      #   params
      # end
    end
    
    def around_generate(*args, &block)
      params = args.extract_options!
      yield.tap do |result|
        result = result.is_a?(Array) ? result.first : result
        if result =~ /^\/(#{CONTROLLER_RE})\/(#{NAME_WITH_FORMAT_RE})\/repositories\/(#{NAME_WITH_FORMAT_RE})(.+)?/i && !reserved_action_name?($3, $1)
          result.replace "/#{PREFIXES_TO_CONTROLLER.invert[$1]}#{$2}/#{$3}#{$4}"
        elsif result =~ /^\/(#{CONTROLLER_RE})\/(#{NAME_WITH_FORMAT_RE})(.+)?/i && !reserved_action_name?($2, $1)
          controller, id, repo = [$1, $2, $3]
          if repo =~ /\/projects\/(#{NAME_WITH_FORMAT_RE})\/repositories\/(#{NAME_WITH_FORMAT_RE})(.+)?/i
            #result.replace "/#{PREFIXES_TO_CONTROLLER.invert[controller]}#{id}#{repo}"
            result.replace "/#{PREFIXES_TO_CONTROLLER.invert[controller]}#{id}/#{$1}/#{$2}#{$3}"
          else
            result.replace "/#{PREFIXES_TO_CONTROLLER.invert[controller]}#{id}#{repo}"
          end
        end
      end
    end
    
    private
      def reserved?(path, controller = nil)
        path_with_ending_slash = path.chomp("/") + "/" # Make sure we always only got one slash
        (CONTROLLER_NAMES + reserved_actions_for_controller(controller)).any? {|s| 
          path_with_ending_slash =~ /^\/#{s}(\..+)?\//
        }
      end
      
      def reserved_action_name?(name, controller)
        reserved_actions_for_controller(controller).include?(name)
      end
      
      def reserved_actions_for_controller(controller)
        case controller
        when "users"
          UsersController.action_methods.to_a
        when "projects"
          ProjectsController.action_methods.to_a
        when "groups", "teams"
          GroupsController.action_methods.to_a
        when "repositories"
          RepositoriesController.action_methods.to_a
        else
          []
        end
      end
      
      def repository_scope?(path)
        !Gitorious::Reservations.projects_member_actions.include?(path.sub("/", "")) && 
          path =~ /^\/(#{NAME_WITH_FORMAT_RE})(.+)?$/i
      end
  end
end