#coding=utf-8
#
require 'rack/auth/basic'
require 'rack/auth/abstract/handler'
require 'rack/auth/abstract/request'

module Grack

  class Auth < Rack::Auth::Basic
    DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
    PUSH_COMMANDS = %w{ git-receive-pack }

    attr_accessor :user, :repository
    def call(env)
      @env = env
      @request = Rack::Request.new(env)
      @auth = Request.new(env)

      if not @auth.provided?
        unauthorized
      elsif not @auth.basic?
        bad_request
      else
        result = if (access = valid?(@auth) and access == true)
          @env['REMOTE_USER'] = @auth.username
          env['REP_PATH'] = repository.root_url 
          @app.call(env)
        else
          if access == '404'
            render_not_found
          elsif access == '403'
            #render_no_access
            unauthorized
          else
            unauthorized
          end
        end
        result
      end
    end# method call


    def render_not_found
      [404, {"Content-Type" => "text/plain"}, ["Not Found"]]
    end

    def valid?(auth)
      self.repository = auth_rep
      return "404" unless repository
      username, password = auth.credentials
      self.user = auth_user(username, password)
      return '403' unless user
      access = auth_request
      puts "access #{access}"
      access
    end

    def auth_rep
      rep = nil
      match = @request.path_info.match(/(\/.+\.git)\//)
      if match
        rep = Repository.where("root_url like ?", "%#{match[1]}").first
      end
      rep
    end

    def auth_user(username, password)
        u, last_login_on = User.try_to_login(username, password)
        unless u && (u.member_of?(repository.project) || u.admin?)
          u = nil
        end
        u
    end

    def auth_request
      case git_cmd
      when *DOWNLOAD_COMMANDS
        user != nil
      when *PUSH_COMMANDS
        unless user
          false
        else
          ### 只有Manager和Development才有push权限
          repository.project.members.where(user_id: user.id).first.roles.any?{|r| r.name == 'Manager' || r.name == 'Developer'}
        end
      else
        false
      end
    end

    def git_cmd
      if @request.get?
        @request.params['service']
      elsif @request.post?
        File.basename(@request.path)
      else
        nil
      end
    end

  end# class Auth
end# module Grack

