-
Notifications
You must be signed in to change notification settings - Fork 516
/
Copy pathbookmarks_controller.rb
225 lines (196 loc) · 8.38 KB
/
bookmarks_controller.rb
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
class Api::V2::BookmarksController < Api::V2::BaseController
respond_to :json
# POST - search for bookmarks for this archivist
def search
archivist = User.find_by(login: params[:archivist])
bookmarks = params[:bookmarks]
# check for top-level errors (not an archivist, no bookmarks...)
status, messages = batch_errors(archivist, bookmarks)
results = []
if status == :ok
archivist_bookmarks = Bookmark.where(pseud_id: archivist.default_pseud.id)
results = bookmarks.map do |bookmark|
found_result = {}
found_result = check_archivist_bookmark(archivist, bookmark[:url], archivist_bookmarks) unless archivist_bookmarks.empty?
bookmark_response(
status: found_result[:bookmark_status] || :not_found,
bookmark_url: found_result[:bookmark_url] || "",
bookmark_id: bookmark[:id],
original_url: bookmark[:url],
messages: found_result[:bookmark_messages] || ["No bookmark found for archivist \"#{archivist.login}\" and URL \"#{bookmark[:url]}\""]
)
end
messages = ["Successfully searched bookmarks for archivist '#{archivist.login}'"]
end
render_api_response(status, messages, bookmarks: results)
end
# POST - create a bookmark for this archivist
def create
archivist = User.find_by(login: params[:archivist])
bookmarks = params[:bookmarks]
bookmarks_responses = []
@bookmarks = []
# check for top-level errors (not an archivist, no bookmarks...)
status, messages = batch_errors(archivist, bookmarks)
if status == :ok
# Flag error and successes
@some_errors = @some_success = false
# Process the bookmarks
archivist_bookmarks = Bookmark.where(pseud_id: archivist.default_pseud_id, bookmarkable_type: "ExternalWork")
bookmarks.each do |bookmark|
bookmarks_responses << create_bookmark(archivist, bookmark, archivist_bookmarks)
end
# set final response code and message depending on the flags
status = :bad_request if bookmarks_responses.any? { |r| [:ok, :created, :found].exclude?(r[:status]) }
messages = response_message(messages)
end
render_api_response(status, messages, bookmarks: bookmarks_responses)
end
private
# Find bookmarks for this archivist
def check_archivist_bookmark(archivist, current_bookmark_url, archivist_bookmarks)
archivist_bookmarks = archivist_bookmarks
.select { |b| b&.bookmarkable.is_a?(ExternalWork) ? b&.bookmarkable&.url == current_bookmark_url : false }
.map { |b| [b, b.bookmarkable] }
if archivist_bookmarks.present?
archivist_bookmark, archivist_bookmarkable = archivist_bookmarks.first
find_bookmark_response(
bookmarkable: archivist_bookmarkable,
bookmark_status: :found,
bookmark_message: "There is already a bookmark for #{archivist.login} and the URL #{current_bookmark_url}",
bookmark_url: bookmark_url(archivist_bookmark)
)
else
find_bookmark_response(
bookmarkable: nil,
bookmark_status: :not_found,
bookmark_message: "There is no bookmark for #{archivist.login} and the URL #{current_bookmark_url}",
bookmark_url: ""
)
end
end
# Create a bookmark for this archivist using the Bookmark model
def create_bookmark(archivist, params, archivist_bookmarks)
found_result = {}
bookmark_request = bookmark_request(archivist, params)
bookmark_status, bookmark_messages = bookmark_errors(bookmark_request)
bookmark_url = nil
original_url = nil
bookmarkable = nil
@some_errors = true
if bookmark_status == :ok
begin
# Check if this bookmark is already imported by filtering the archivist's bookmarks
unless archivist_bookmarks.empty?
found_result = check_archivist_bookmark(archivist, bookmark_request[:external][:url], archivist_bookmarks)
bookmarkable = found_result[:bookmarkable]
end
if found_result[:bookmark_status] == :found
found_result[:bookmark_status] = :already_imported
else
bookmark = Bookmark.new(bookmark_request)
bookmarkable = bookmark.bookmarkable
if bookmarkable.save && bookmark.save
@bookmarks << bookmark
@some_success = true
@some_errors = false
bookmark_status = :created
bookmark_url = bookmark_url(bookmark)
bookmark_messages << "Successfully created bookmark for \"" + bookmarkable.title + "\"."
else
bookmark_status = :unprocessable_entity
bookmark_messages << bookmarkable.errors.full_messages + bookmark.errors.full_messages
end
end
rescue StandardError => exception
bookmark_status = :unprocessable_entity
bookmark_messages << exception.message
end
original_url = bookmarkable.url if bookmarkable
end
bookmark_response(
status: bookmark_status || found_result[:bookmark_status],
bookmark_url: bookmark_url || found_result[:bookmark_url],
bookmark_id: params[:id],
original_url: original_url,
messages: bookmark_messages.flatten || found_result[:bookmark_messages]
)
end
# Error handling
# Set messages based on success and error flags
def response_message(messages)
messages << if @some_success && @some_errors
"At least one bookmark was not created. Please check the individual bookmark results for further information."
elsif !@some_success && @some_errors
"None of the bookmarks were created. Please check the individual bookmark results for further information."
else
"All bookmarks were successfully created."
end
messages
end
# Handling for incomplete requests
def bookmark_errors(bookmark_request)
status = :bad_request
errors = []
# Perform basic validation which the ExternalWork model doesn't do or returns strange messages for
# (title is validated correctly in the model and so isn't checked here)
external_work = bookmark_request[:external]
url = external_work[:url]
author = external_work[:author]
fandom = external_work[:fandom_string]
if url.nil?
# Unreachable and AO3 URLs are handled in the ExternalWork model
errors << "This bookmark does not contain a URL to an external site. Please specify a valid, non-AO3 URL."
end
if author.nil? || author == ""
errors << "This bookmark does not contain an external author name. Please specify an author."
end
if fandom.nil? || fandom == ""
errors << "This bookmark does not contain a fandom. Please specify a fandom."
end
status = :ok if errors.empty?
[status, errors]
end
# Request and response hashes
# Map Json request to Bookmark request for external work
def bookmark_request(archivist, params)
{
pseud_id: archivist.default_pseud_id,
external: {
url: params[:url],
author: params[:author],
title: params[:title],
summary: params[:summary],
fandom_string: params[:fandom_string] || "",
rating_string: params[:rating_string] || "",
category_string: params[:category_string] ? params[:category_string].to_s.split(",") : [], # category is actually an array on bookmarks
relationship_string: params[:relationship_string] || "",
character_string: params[:character_string] || ""
},
bookmarker_notes: params[:bookmarker_notes],
tag_string: params[:tag_string] || "",
collection_names: params[:collection_names],
private: params[:private].blank? ? false : params[:private],
rec: params[:recommendation].blank? ? false : params[:recommendation]
}
end
def bookmark_response(status:, bookmark_url:, bookmark_id:, original_url:, messages:)
messages = [messages] unless messages.respond_to?('each')
{
status: status,
archive_url: bookmark_url,
original_id: bookmark_id,
original_url: original_url,
messages: messages
}
end
def find_bookmark_response(bookmarkable:, bookmark_status:, bookmark_message:, bookmark_url:)
bookmark_status = :not_found unless [:found, :not_found].include?(bookmark_status)
{
bookmarkable: bookmarkable,
bookmark_status: bookmark_status,
bookmark_messages: bookmark_message,
bookmark_url: bookmark_url
}
end
end