Skip to content

Commit 85501dc

Browse files
authored
Update /assets endpoint (#713)
* Assets: remove role validation in model * AssetsController: update API endpoint and validation The endpoint is updated to `/v2/admin/assets`, and validation is performed within the router instead. * Shift to `AdminAssetsController` * Rename `AdminAssetsController` to `.exs` * Assets: switch to `case` instead of `with`
1 parent 5d6ae4d commit 85501dc

File tree

6 files changed

+46
-61
lines changed

6 files changed

+46
-61
lines changed

lib/cadet/assets/assets.ex

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,14 @@ defmodule Cadet.Assets.Assets do
55
Assessments context contains domain logic for assets management
66
for Source academy's game component
77
"""
8-
@manage_assets_role ~w(staff admin)a
9-
108
@accessible_folders ~w(images locations objects avatars ui stories sfx bgm) ++
119
if(Mix.env() == :test, do: ["testFolder"], else: [])
1210
@accepted_file_types ~w(.jpg .jpeg .gif .png .wav .mp3 .txt)
1311

14-
def upload_to_s3(upload_params, folder_name, file_name, user) do
12+
def upload_to_s3(upload_params, folder_name, file_name) do
1513
file_type = Path.extname(file_name)
1614

17-
with :ok <- validate_role(user.role),
18-
:ok <- validate_file_name(file_name),
15+
with :ok <- validate_file_name(file_name),
1916
:ok <- validate_folder_name(folder_name),
2017
:ok <- validate_file_type(file_type) do
2118
if object_exists?(folder_name, file_name) do
@@ -35,19 +32,21 @@ defmodule Cadet.Assets.Assets do
3532
end
3633
end
3734

38-
def list_assets(folder_name, user) do
39-
with :ok <- validate_role(user.role),
40-
:ok <- validate_folder_name(folder_name) do
41-
bucket()
42-
|> S3.list_objects(prefix: folder_name <> "/")
43-
|> ExAws.stream!()
44-
|> Enum.map(fn file -> file.key end)
35+
def list_assets(folder_name) do
36+
case validate_folder_name(folder_name) do
37+
:ok ->
38+
bucket()
39+
|> S3.list_objects(prefix: folder_name <> "/")
40+
|> ExAws.stream!()
41+
|> Enum.map(fn file -> file.key end)
42+
43+
{:error, _} = error ->
44+
error
4545
end
4646
end
4747

48-
def delete_object(folder_name, file_name, user) do
49-
with :ok <- validate_role(user.role),
50-
:ok <- validate_file_name(file_name),
48+
def delete_object(folder_name, file_name) do
49+
with :ok <- validate_file_name(file_name),
5150
:ok <- validate_folder_name(folder_name) do
5251
if object_exists?(folder_name, file_name) do
5352
bucket()
@@ -71,14 +70,6 @@ defmodule Cadet.Assets.Assets do
7170
end
7271
end
7372

74-
defp validate_role(role) do
75-
if role in @manage_assets_role do
76-
:ok
77-
else
78-
{:error, {:forbidden, "User not allowed to manage assets"}}
79-
end
80-
end
81-
8273
defp validate_folder_name(folder_name) do
8374
if folder_name in @accessible_folders do
8475
:ok

lib/cadet_web/controllers/assets_controller.ex renamed to lib/cadet_web/admin_controllers/admin_assets_controller.ex

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
defmodule CadetWeb.AssetsController do
1+
defmodule CadetWeb.AdminAssetsController do
22
use CadetWeb, :controller
33

44
use PhoenixSwagger
55
alias Cadet.Assets.Assets
66

77
def index(conn, _params = %{"foldername" => foldername}) do
8-
case Assets.list_assets(foldername, conn.assigns.current_user) do
8+
case Assets.list_assets(foldername) do
99
{:error, {status, message}} -> conn |> put_status(status) |> text(message)
1010
assets -> render(conn, "index.json", assets: assets)
1111
end
@@ -15,7 +15,7 @@ defmodule CadetWeb.AssetsController do
1515
def delete(conn, _params = %{"foldername" => foldername, "filename" => filename}) do
1616
filename = Enum.join(filename, "/")
1717

18-
case Assets.delete_object(foldername, filename, conn.assigns.current_user) do
18+
case Assets.delete_object(foldername, filename) do
1919
{:error, {status, message}} -> conn |> put_status(status) |> text(message)
2020
_ -> conn |> put_status(204) |> text('')
2121
end
@@ -28,7 +28,7 @@ defmodule CadetWeb.AssetsController do
2828
}) do
2929
filename = Enum.join(filename, "/")
3030

31-
case Assets.upload_to_s3(upload_params, foldername, filename, conn.assigns.current_user) do
31+
case Assets.upload_to_s3(upload_params, foldername, filename) do
3232
{:error, {status, message}} -> conn |> put_status(status) |> text(message)
3333
resp -> render(conn, "show.json", resp: resp)
3434
end
@@ -60,7 +60,7 @@ defmodule CadetWeb.AssetsController do
6060
end
6161

6262
swagger_path :index do
63-
get("/assets/{foldername}")
63+
get("/admin/assets/{foldername}")
6464

6565
summary("Get a list of all assets in a folder")
6666

@@ -78,7 +78,7 @@ defmodule CadetWeb.AssetsController do
7878
end
7979

8080
swagger_path :delete do
81-
PhoenixSwagger.Path.delete("/assets/{foldername}/{filename}")
81+
PhoenixSwagger.Path.delete("/admin/assets/{foldername}/{filename}")
8282

8383
summary("Delete a file from an asset folder")
8484

@@ -90,16 +90,14 @@ defmodule CadetWeb.AssetsController do
9090

9191
security([%{JWT: []}])
9292

93-
produces("application/json")
94-
9593
response(204, "OK")
9694
response(400, "Invalid folder name, file name or file type")
9795
response(403, "User is not allowed to manage assets")
9896
response(404, "File not found")
9997
end
10098

10199
swagger_path :upload do
102-
post("/assets/{foldername}/{filename}")
100+
post("/admin/assets/{foldername}/{filename}")
103101

104102
summary("Upload a file to an asset folder")
105103

lib/cadet_web/views/assets_view.ex renamed to lib/cadet_web/admin_views/admin_assets_view.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
defmodule CadetWeb.AssetsView do
1+
defmodule CadetWeb.AdminAssetsView do
22
use CadetWeb, :view
33
use Timex
44

55
def render("index.json", %{assets: assets}) do
6-
render_many(assets, CadetWeb.AssetsView, "show.json", as: :asset)
6+
render_many(assets, CadetWeb.AdminAssetsView, "show.json", as: :asset)
77
end
88

99
def render("show.json", %{asset: asset}) do

lib/cadet_web/router.ex

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ defmodule CadetWeb.Router do
6666
delete("/stories/:storyid", StoriesController, :delete)
6767
post("/stories/:storyid", StoriesController, :update)
6868

69-
get("/assets/:foldername", AssetsController, :index)
70-
post("/assets/:foldername/*filename", AssetsController, :upload)
71-
delete("/assets/:foldername/*filename", AssetsController, :delete)
72-
7369
get("/grading", GradingController, :index)
7470
get("/grading/summary", GradingController, :grading_summary)
7571
get("/grading/:submissionid", GradingController, :show)
@@ -115,6 +111,14 @@ defmodule CadetWeb.Router do
115111
delete("/goals/:uuid", AdminGoalsController, :delete)
116112
end
117113

114+
scope "/v2/admin", CadetWeb do
115+
pipe_through([:api, :auth, :ensure_auth, :ensure_staff])
116+
117+
get("/assets/:foldername", AdminAssetsController, :index)
118+
post("/assets/:foldername/*filename", AdminAssetsController, :upload)
119+
delete("/assets/:foldername/*filename", AdminAssetsController, :delete)
120+
end
121+
118122
# Other scopes may use custom stacks.
119123
# scope "/api", CadetWeb do
120124
# pipe_through :api

test/cadet/assets/assets_test.exs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,50 @@
11
defmodule Cadet.Assets.AssetsTest do
22
alias Cadet.Assets.Assets
3-
alias Cadet.Accounts.User
43

54
use ExUnit.Case, async: true
65
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
76

87
describe "Manage assets" do
9-
@tag authenticate: :staff
108
test "accessible folder" do
119
use_cassette "aws/model_list_assets#1" do
12-
assert Assets.list_assets("testFolder", %User{role: :staff}) === [
10+
assert Assets.list_assets("testFolder") === [
1311
"testFolder/",
1412
"testFolder/test.png",
1513
"testFolder/test2.png"
1614
]
1715
end
1816
end
1917

20-
@tag authenticate: :staff
2118
test "delete nonexistent file" do
2219
use_cassette "aws/model_delete_asset#1" do
23-
assert Assets.delete_object("testFolder", "test4.png", %User{role: :staff}) ===
20+
assert Assets.delete_object("testFolder", "test4.png") ===
2421
{:error, {:not_found, "File not found"}}
2522
end
2623
end
2724

28-
@tag authenticate: :staff
2925
test "delete ok file" do
3026
use_cassette "aws/model_delete_asset#2" do
31-
assert Assets.delete_object("testFolder", "test.png", %User{role: :staff}) === :ok
27+
assert Assets.delete_object("testFolder", "test.png") === :ok
3228
end
3329
end
3430

35-
@tag authenticate: :staff
3631
test "upload existing file" do
3732
use_cassette "aws/model_upload_asset#1" do
3833
assert Assets.upload_to_s3(
3934
build_upload("test/fixtures/upload.png"),
4035
"testFolder",
41-
"test2.png",
42-
%User{role: :staff}
36+
"test2.png"
4337
) ===
4438
{:error, {:bad_request, "File already exists"}}
4539
end
4640
end
4741

48-
@tag authenticate: :staff
4942
test "upload ok file" do
5043
use_cassette "aws/model_upload_asset#2" do
5144
assert Assets.upload_to_s3(
5245
build_upload("test/fixtures/upload.png"),
5346
"testFolder",
54-
"test1.png",
55-
%User{role: :staff}
47+
"test1.png"
5648
) ===
5749
"https://source-academy-assets.s3.amazonaws.com/testFolder/test1.png"
5850
end

test/cadet_web/controllers/assets_controller_test.exs renamed to test/cadet_web/admin_controllers/assets_controller_test.exs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
defmodule CadetWeb.AssetsControllerTest do
1+
defmodule CadetWeb.AdminAssetsControllerTest do
22
use CadetWeb.ConnCase
33
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
44

5-
alias CadetWeb.AssetsController
5+
alias CadetWeb.AdminAssetsController
66

77
setup_all do
88
HTTPoison.start()
99
end
1010

1111
test "swagger" do
12-
AssetsController.swagger_definitions()
13-
AssetsController.swagger_path_index(nil)
14-
AssetsController.swagger_path_upload(nil)
15-
AssetsController.swagger_path_delete(nil)
12+
AdminAssetsController.swagger_definitions()
13+
AdminAssetsController.swagger_path_index(nil)
14+
AdminAssetsController.swagger_path_upload(nil)
15+
AdminAssetsController.swagger_path_delete(nil)
1616
end
1717

1818
describe "public access, unauthenticated" do
@@ -36,14 +36,14 @@ defmodule CadetWeb.AssetsControllerTest do
3636
@tag authenticate: :student
3737
test "GET /assets/:foldername", %{conn: conn} do
3838
conn = get(conn, build_url("testFolder"), %{})
39-
assert response(conn, 403) =~ "User not allowed to manage assets"
39+
assert response(conn, 403) =~ "Forbidden"
4040
end
4141

4242
@tag authenticate: :student
4343
test "DELETE /assets/:foldername/*filename", %{conn: conn} do
4444
conn = delete(conn, build_url("testFolder/testFile.png"))
4545

46-
assert response(conn, 403) =~ "User not allowed to manage assets"
46+
assert response(conn, 403) =~ "Forbidden"
4747
end
4848

4949
@tag authenticate: :student
@@ -53,7 +53,7 @@ defmodule CadetWeb.AssetsControllerTest do
5353
:upload => build_upload("test/fixtures/upload.png")
5454
})
5555

56-
assert response(conn, 403) =~ "User not allowed to manage assets"
56+
assert response(conn, 403) =~ "Forbidden"
5757
end
5858
end
5959

@@ -170,7 +170,7 @@ defmodule CadetWeb.AssetsControllerTest do
170170
end
171171
end
172172

173-
defp build_url, do: "/v1/assets/"
173+
defp build_url, do: "/v2/admin/assets/"
174174
defp build_url(url), do: "#{build_url()}/#{url}"
175175

176176
defp build_upload(path, content_type \\ "image/png") do

0 commit comments

Comments
 (0)