app.rb 6.5 KB

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