app.rb 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. require 'flickr/login'
  2. require 'flickraw'
  3. require 'pry'
  4. require 'sinatra'
  5. require 'sinatra/config_file'
  6. require 'sinatra/json'
  7. require 'sinatra/reloader'
  8. require 'sinatra/sequel'
  9. config_file 'config.yml'
  10. enable :sessions
  11. set :database, 'sqlite://db.sqlite3'
  12. migration 'create users, licenses, and photos tables' do
  13. database.create_table :users do
  14. column :nsid, String, primary_key: true
  15. column :username, String
  16. column :fullname, String
  17. end
  18. database.create_table :licenses do
  19. column :id, Integer, primary_key: true
  20. column :name, String
  21. column :url, String
  22. end
  23. database.create_table :photos do
  24. column :id, Integer, primary_key: true
  25. # foreign_key :user_id, :users, on_delete: :cascade, on_update: :restrict
  26. foreign_key :owner, :users
  27. # foreign_key :license_id, :licenses, on_delete: :cascade, on_update: :restrict
  28. foreign_key :license, :licenses
  29. column :json, 'text'
  30. column :ignore, 'boolean'
  31. end
  32. end
  33. migration 'rename photo owner and license columns to user_id and license_id' do
  34. database.alter_table :photos do
  35. drop_foreign_key [:owner]
  36. rename_column :owner, :user_id
  37. add_foreign_key [:user_id], :users
  38. drop_foreign_key [:license]
  39. rename_column :license, :license_id
  40. add_foreign_key [:license_id], :licenses
  41. end
  42. end
  43. migration 'add on delete and update constraints to photo user_id and license_id' do
  44. database.alter_table :photos do
  45. drop_foreign_key [:user_id]
  46. add_foreign_key [:user_id], :users, on_delete: :cascade, on_update: :restrict
  47. drop_foreign_key [:license_id]
  48. add_foreign_key [:license_id], :licenses, on_delete: :cascade, on_update: :restrict
  49. end
  50. end
  51. migration 'add not null constraint to photo user_id and license_id' do
  52. database.alter_table :photos do
  53. set_column_not_null :user_id
  54. set_column_not_null :license_id
  55. end
  56. end
  57. class User < Sequel::Model
  58. one_to_many :photos
  59. unrestrict_primary_key
  60. end
  61. class License < Sequel::Model
  62. one_to_many :photos
  63. unrestrict_primary_key
  64. def as_json(*)
  65. {
  66. id: id,
  67. name: name,
  68. url: url,
  69. }
  70. end
  71. def to_json(*args)
  72. as_json.to_json(*args)
  73. end
  74. end
  75. class Photo < Sequel::Model
  76. many_to_one :user
  77. many_to_one :license
  78. unrestrict_primary_key
  79. def flickraw
  80. @flickraw ||= OpenStruct.new(JSON.parse(json))
  81. end
  82. def as_json(*)
  83. {
  84. id: id,
  85. license: license_id,
  86. ignore: ignore,
  87. img: FlickRaw.url_q(flickraw),
  88. url: FlickRaw.url_photopage(flickraw),
  89. title: flickraw.title,
  90. public: flickraw.ispublic != 0,
  91. friend: flickraw.isfriend != 0,
  92. family: flickraw.isfamily != 0,
  93. }
  94. end
  95. def to_json(*args)
  96. as_json.to_json(*args)
  97. end
  98. end
  99. helpers Flickr::Login::Helpers
  100. helpers do
  101. def flickr
  102. unless @flickr
  103. @flickr = FlickRaw::Flickr.new(api_key: settings.flickr_api_key, shared_secret: settings.flickr_shared_secret)
  104. @flickr.access_token, @flickr.access_secret = flickr_access_token
  105. end
  106. @flickr
  107. end
  108. end
  109. before do
  110. redirect to('/login?perms=write') unless flickr_user
  111. @user = User.find_or_create(nsid: flickr_user[:user_nsid]) do |user|
  112. user.username = flickr_user[:username]
  113. user.fullname = flickr_user[:fullname]
  114. end
  115. end
  116. get '/' do
  117. @licenses = License.all
  118. @licenses = flickr.photos.licenses.getInfo.map do |flickr_license|
  119. License.create do |license|
  120. license.id = flickr_license.id
  121. license.name = flickr_license.name
  122. license.url = flickr_license.url
  123. end
  124. end if @licenses.count == 0
  125. erb :index
  126. end
  127. get '/logout' do
  128. flickr_clear
  129. redirect to('/')
  130. end
  131. get %r{/photos/([1-8])} do |page|
  132. @user.photos_dataset.delete if params['reload'] == 'true'
  133. page, per_page = page.to_i, 500
  134. photos = @user.photos_dataset.reverse(:id).limit(per_page, (page - 1) * per_page).all
  135. begin
  136. photos = flickr.photos.search(user_id: :me, extras: 'license', per_page: per_page, page: page).map do |flickr_photo|
  137. Photo.create do |photo|
  138. photo.id = flickr_photo.id
  139. photo.user = @user
  140. photo.license_id = flickr_photo.license
  141. photo.json = flickr_photo.to_hash.to_json
  142. photo.ignore = false
  143. end
  144. end if photos.count == 0
  145. rescue FlickRaw::Error => e
  146. halt 422, json(error: e.message)
  147. rescue Sequel::UniqueConstraintViolation
  148. # sometimes the Flickr API will just keep repeating the same results for subsequent pages
  149. end
  150. halt json path: "/photos/#{page + 1}", photos: photos if photos.count == per_page && page < 8
  151. json photos: photos
  152. end
  153. post '/photos' do
  154. ignore = params['ignore'] == 'true'
  155. ids = params['photos'] && params['photos'].is_a?(Array) ? params['photos'] : [params['photo']]
  156. photos = @user.photos_dataset.where(id: ids)
  157. halt 404, json(error: "Could not find photo(s) with ID(s): #{ids.map(&:to_i) - photos.map(:id)}") unless photos.count == ids.size
  158. photos.update(ignore: ignore)
  159. status 204
  160. end
  161. post '/photos/*' do |id|
  162. photo = @user.photos_dataset.where(id: id).first
  163. halt 404, json(error: "Could not find photo with ID: #{id}") unless photo
  164. license_id = params['license'] && params['license'].to_i
  165. license = License[license_id]
  166. halt 422, json(error: "Could not find license with ID: #{license_id.inspect}") unless license
  167. halt 422, json(error: "Could not change license of ignored photo") if photo.ignore
  168. begin
  169. flickr.photos.licenses.setLicense(photo_id: photo.id, license_id: license.id)
  170. rescue FlickRaw::Error => e
  171. halt 422, json(error: e.message)
  172. end
  173. photo.update(license: license)
  174. status 204
  175. end