Meet SourceLevel, an All-in-one Data & Analytics for Engineering Teams

SourceLevel provides metrics and insights by collecting data from many sources such as GitHub and GitLab. Our product brings visibility over every corner of the delivery pipeline in a Data & Analytics Solution for Engineering Teams.

Get started for free
Go to line 1
defmodule HexpmWeb.PackageController do
Go to line 2
  use HexpmWeb, :controller
Go to line 4
  @packages_per_page 30
Go to line 5
  @audit_logs_per_page 10
Go to line 6
  @sort_params ~w(name recent_downloads total_downloads inserted_at updated_at recently_published)
Go to line 7
  @letters for letter <- ?A..?Z, do: <<letter>>
Go to line 9
  def index(conn, params) do
Go to line 10
    letter = Hexpm.Utils.parse_search(params["letter"])
Go to line 11
    search = Hexpm.Utils.parse_search(params["search"])
Go to line 15
        letter ->
Go to line 16
          {:letter, letter}
Go to line 18
        search ->
Go to line 25
    organizations = Users.all_organizations(conn.assigns.current_user)
Go to line 26
    repositories = Enum.map(organizations, & &1.repository)
Go to line 27
    sort = sort(params["sort"])
Go to line 28
    page_param = Hexpm.Utils.safe_int(params["page"]) || 1
Go to line 29
    package_count = Packages.count(repositories, filter)
Go to line 30
    page = Hexpm.Utils.safe_page(page_param, package_count, @packages_per_page)
Go to line 31
    packages = fetch_packages(repositories, page, @packages_per_page, filter, sort)
Go to line 32
    downloads = Packages.packages_downloads_with_all_views(packages)
Go to line 33
    exact_match = exact_match(repositories, search)
Go to line 37
      "index.html",
Go to line 38
      title: "Packages",
Go to line 39
      container: "container",
Go to line 40
      per_page: @packages_per_page,
Go to line 41
      search: search,
Go to line 42
      letter: letter,
Go to line 43
      sort: sort,
Go to line 44
      package_count: package_count,
Go to line 45
      page: page,
Go to line 46
      packages: packages,
Go to line 47
      letters: @letters,
Go to line 48
      downloads: downloads,
Go to line 49
      exact_match: exact_match
Go to line 53
  def show(conn, params) do
Go to line 54
    # TODO: Show flash if private package and organization does not have active billing
Go to line 56
    params = fixup_params(params)
Go to line 58
    access_package(conn, params, fn package, repositories ->
Go to line 59
      releases = Releases.all(package)
Go to line 61
      {release, type} =
Go to line 62
        if version = params["version"] do
Go to line 63
          {matching_release(releases, version), :release}
Go to line 65
          {Release.latest_version(releases, only_stable: true, unstable_fallback: true), :package}
Go to line 68
      if release do
Go to line 69
        package(conn, repositories, package, releases, release, type)
Go to line 71
        not_found(conn)
Go to line 76
  def audit_logs(conn, params) do
Go to line 77
    access_package(conn, params, fn package, _ ->
Go to line 78
      page = Hexpm.Utils.safe_int(params["page"]) || 1
Go to line 79
      per_page = 100
Go to line 80
      audit_logs = AuditLogs.all_by(package, page, per_page)
Go to line 81
      total_count = AuditLogs.count_by(package)
Go to line 83
      render(conn, "audit_logs.html",
Go to line 84
        title: "Recent Activities for #{package.name}",
Go to line 85
        container: "container package-view",
Go to line 86
        package: package,
Go to line 87
        audit_logs: audit_logs,
Go to line 88
        page: page,
Go to line 89
        per_page: per_page,
Go to line 90
        total_count: total_count
Go to line 95
  defp access_package(conn, params, fun) do
Go to line 96
    %{"repository" => repository, "name" => name} = params
Go to line 97
    organizations = Users.all_organizations(conn.assigns.current_user)
Go to line 98
    repositories = Map.new(organizations, &{&1.repository.name, &1.repository})
Go to line 100
    if repository = repositories[repository] do
Go to line 101
      package = repository && Packages.get(repository, name)
Go to line 103
      # Should have access even though organization does not have active billing
Go to line 104
      if package do
Go to line 105
        fun.(package, Enum.map(organizations, & &1.repository))
Go to line 107
    end || not_found(conn)
Go to line 110
  defp sort(nil), do: sort("recent_downloads")
Go to line 111
  defp sort("downloads"), do: sort("recent_downloads")
Go to line 112
  defp sort(param), do: Hexpm.Utils.safe_to_atom(param, @sort_params)
Go to line 114
  defp matching_release(releases, version) do
Go to line 115
    Enum.find(releases, &(to_string(&1.version) == version))
Go to line 118
  defp package(conn, repositories, package, releases, release, type) do
Go to line 119
    repository = package.repository
Go to line 120
    release = Releases.preload(release, [:requirements, :downloads, :publisher])
Go to line 122
    latest_release_with_docs =
Go to line 123
      Release.latest_version(releases, only_stable: true, unstable_fallback: true, with_docs: true)
Go to line 125
    docs_assigns =
Go to line 127
        type == :package && latest_release_with_docs ->
Go to line 129
            docs_html_url: Hexpm.Utils.docs_html_url(repository, package, nil),
Go to line 130
            docs_tarball_url:
Go to line 131
              Hexpm.Utils.docs_tarball_url(repository, package, latest_release_with_docs)
Go to line 134
        type == :release and release.has_docs ->
Go to line 136
            docs_html_url: Hexpm.Utils.docs_html_url(repository, package, release),
Go to line 137
            docs_tarball_url: Hexpm.Utils.docs_tarball_url(repository, package, release)
Go to line 141
          [docs_html_url: nil, docs_tarball_url: nil]
Go to line 144
    downloads = Packages.package_downloads(package)
Go to line 146
    graph_downloads =
Go to line 147
      case type do
Go to line 148
        :package -> Enum.map(releases, & &1.id) |> Releases.downloads_for_last_n_days(31)
Go to line 149
        :release -> release.id |> Releases.downloads_for_last_n_days(31)
Go to line 152
    daily_graph =
Go to line 153
      Date.utc_today()
Go to line 154
      |> Date.add(-31)
Go to line 155
      |> Date.range(Date.add(Date.utc_today(), -1))
Go to line 156
      |> Enum.map(fn date ->
Go to line 157
        Enum.find(graph_downloads, fn dl -> date == Date.from_iso8601!(dl.day) end)
Go to line 159
      |> Enum.map(fn
Go to line 161
        %{downloads: dl} -> dl
Go to line 164
    owners = Owners.all(package, user: [:emails, :organization])
Go to line 166
    dependants =
Go to line 167
      Packages.search(
Go to line 168
        repositories,
Go to line 171
        "depends:#{repository.name}:#{package.name}",
Go to line 172
        :recent_downloads,
Go to line 173
        [:name, :repository_id]
Go to line 176
    dependants_count = Packages.count(repositories, "depends:#{repository.name}:#{package.name}")
Go to line 178
    audit_logs = AuditLogs.all_by(package, 1, @audit_logs_per_page)
Go to line 182
      "show.html",
Go to line 184
        title: package.name,
Go to line 185
        description: package.meta.description,
Go to line 186
        container: "container package-view",
Go to line 187
        canonical_url: Routes.package_url(conn, :show, package),
Go to line 188
        package: package,
Go to line 189
        repository_name: repository.name,
Go to line 190
        releases: releases,
Go to line 191
        current_release: release,
Go to line 192
        downloads: downloads,
Go to line 193
        owners: owners,
Go to line 194
        dependants: dependants,
Go to line 195
        dependants_count: dependants_count,
Go to line 196
        audit_logs: audit_logs,
Go to line 197
        daily_graph: daily_graph,
Go to line 198
        type: type
Go to line 199
      ] ++ docs_assigns
Go to line 203
  defp fetch_packages(repositories, page, packages_per_page, search, sort) do
Go to line 204
    packages = Packages.search(repositories, page, packages_per_page, search, sort, nil)
Go to line 205
    Packages.attach_versions(packages)
Go to line 208
  defp exact_match(_organizations, nil) do
Go to line 212
  defp exact_match(repositories, search) do
Go to line 213
    case String.split(search, "/", parts: 2) do
Go to line 214
      [repository, package] ->
Go to line 215
        if repository in Enum.map(repositories, & &1.name) do
Go to line 216
          Packages.get(repository, package)
Go to line 221
          Packages.get(repositories, search)
Go to line 223
          Ecto.MultipleResultsError ->
Go to line 229
  defp fixup_params(%{"name" => name, "version" => version} = params) do
Go to line 230
    case Version.parse(version) do
Go to line 231
      {:ok, _} ->
Go to line 236
        |> Map.put("repository", name)
Go to line 237
        |> Map.put("name", version)
Go to line 238
        |> Map.delete("version")
Go to line 242
  defp fixup_params(params) do