Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add shrimpo models/tables #204

Merged
merged 44 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
c0011a9
add shrimpo models/tables
mcfiredrill Dec 28, 2022
74c0c04
Merge remote-tracking branch 'origin/main' into shrimpo
mcfiredrill Aug 10, 2023
d7c5fab
shrimpo API
mcfiredrill Aug 23, 2023
ccda83a
add shrimpo serializer
mcfiredrill Aug 24, 2023
59c82f1
Merge remote-tracking branch 'origin/main' into shrimpo
mcfiredrill Aug 25, 2023
a4eb80f
add direct uploads controller
mcfiredrill Aug 26, 2023
b36cfe8
add shrimpo status
mcfiredrill Aug 27, 2023
262df4d
add shrimpo slug
mcfiredrill Aug 27, 2023
0218487
make sure active storage engine is enabled
mcfiredrill Aug 28, 2023
080ed51
active storage configs
mcfiredrill Aug 29, 2023
8e29add
schema
mcfiredrill Aug 30, 2023
3bde0c0
Merge remote-tracking branch 'origin/main' into shrimpo
mcfiredrill Oct 23, 2023
b288927
shrimpo entries controller
mcfiredrill Oct 25, 2023
edbc49a
more shrimpo stuff
mcfiredrill Nov 6, 2023
6d6e961
Merge remote-tracking branch 'origin/main' into shrimpo
mcfiredrill Jan 20, 2024
1ea0408
shrimpo votes and cats
mcfiredrill Jan 21, 2024
07e0d19
add end shrimpo worker
mcfiredrill Jan 23, 2024
8b61356
doops
mcfiredrill Jan 25, 2024
1201adb
add images to serializer
mcfiredrill Feb 4, 2024
cd4cdca
add slug to shrimpo entries
mcfiredrill Feb 11, 2024
c5144da
entries show API
mcfiredrill Feb 11, 2024
989007c
fix audio upload
mcfiredrill Feb 12, 2024
6b605e3
fix spec
mcfiredrill Feb 13, 2024
08b1bd7
fix end shrimpo worker
mcfiredrill Feb 14, 2024
b2c0e2e
setup s3 storage
mcfiredrill Feb 15, 2024
5e45fd8
shrimpo vote
mcfiredrill Feb 16, 2024
bfeda0e
save votes
mcfiredrill Feb 17, 2024
9322a9f
fix votes controller
mcfiredrill Feb 17, 2024
52fb622
result tally
mcfiredrill Feb 19, 2024
916e346
add pagination links
mcfiredrill Feb 19, 2024
46f0443
add ended_at_to_shrimpo
mcfiredrill Feb 20, 2024
0c6f4f7
add posts to shrimpos/entries
mcfiredrill Feb 21, 2024
afc661c
add save and deposit method
mcfiredrill Feb 26, 2024
a2c7c05
CERVESZA CRISTALLLL
mcfiredrill Mar 9, 2024
faf03db
dont return deposit if less than 2 entries
mcfiredrill Mar 9, 2024
beff09b
fix saving cover art / zip
mcfiredrill Mar 9, 2024
4cb4a84
add validations
mcfiredrill Mar 9, 2024
5a5cfd1
add username/useravatar to shrimpo_serializer
mcfiredrill Mar 10, 2024
80a8b43
add missing emoji to params
mcfiredrill Mar 10, 2024
a46060f
fix spec
mcfiredrill Mar 10, 2024
a78f2ff
Merge remote-tracking branch 'origin/main' into shrimpo
mcfiredrill Mar 11, 2024
039bb55
not sure what that was
mcfiredrill Mar 13, 2024
e542d6e
we call it shrimpo
mcfiredrill Mar 13, 2024
741a3ef
fix spec
mcfiredrill Mar 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions app/controllers/api/shrimpos/shrimpo_entries/votes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Api::Shrimpos::ShrimpoEntries::VotesController < ApplicationController
def create
shrimpo_entry = ShrimpoEntry.friendly.find params[:shrimpo_entry_id]
vote = ShrimpoVote.find_or_initialize_by shrimpo_entry_id: shrimpo_entry.id, user_id: current_user.id
vote.attributes = shrimpo_vote_params
if vote.save
render json: vote
else
render json: { errors: vote.errors }, status: 422
end
end

private
def shrimpo_vote_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [
:score
])
end
end
26 changes: 26 additions & 0 deletions app/controllers/api/shrimpos/shrimpo_entries_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Api::Shrimpos::ShrimpoEntriesController < ApplicationController
def show
entry = ::Shrimpo.friendly.find(params[:shrimpo_id]).shrimpo_entries.friendly.find(params[:id])
render json: entry, include: ['shrimpo_votes', 'posts']
end

def create
shrimpo = Shrimpo.friendly.find params[:shrimpo_id]
entry = shrimpo.shrimpo_entries.new shrimpo_entry_params
entry.user = current_user

if entry.save
ActiveSupport::Notifications.instrument 'shrimpo.entry.created', title: entry.title, username: entry.user.username
render json: entry
else
render json: { errors: entry.errors }, status: 422
end
end

private
def shrimpo_entry_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [
:title, :audio
])
end
end
29 changes: 29 additions & 0 deletions app/controllers/api/shrimpos_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Api::ShrimposController < ApplicationController
def index
shrimpos = Shrimpo.all
render json: shrimpos
end

def create
shrimpo = Shrimpo.new shrimpo_params
shrimpo.user = current_user
if shrimpo.save_and_deposit_fruit_tickets!
ActiveSupport::Notifications.instrument 'shrimpo.created', username: shrimpo.user.username, title: shrimpo.title
render json: shrimpo
else
render json: { errors: shrimpo.errors }, status: 422
end
end

def show
shrimpo = Shrimpo.friendly.find params[:id]
render json: shrimpo, include: 'shrimpo_entries'
end

private
def shrimpo_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [
:title, :start_at, :end_at, :rule_pack, :duration, :cover_art, :zip, :emoji
])
end
end
4 changes: 4 additions & 0 deletions app/controllers/direct_uploads_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class DirectUploadsController < ActiveStorage::DirectUploadsController
protect_from_forgery with: :exception
skip_before_action :verify_authenticity_token
end
1 change: 1 addition & 0 deletions app/models/experience_point_award.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ExperiencePointAward < ApplicationRecord
:streamingatron, # streaming live
:glorppy, # daily glorp lottery
:gloppy, # daily glop lottery
:shrimpo, # winning shrimpo
]

private
Expand Down
16 changes: 15 additions & 1 deletion app/models/fruit_ticket_transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ class FruitTicketTransaction < ApplicationRecord
:fruit_summon, # metal pineapple, real lemoner, XL shrimp shake
:profile_sticker,

:user_gift
:user_gift,

:shrimpo_deposit,
:shrimpo_deposit_return,
:shrimpo_award,
:shrimpo_playback,
]

def transact_and_save!
Expand Down Expand Up @@ -60,6 +65,15 @@ def transact_and_save!
self.from_user.update fruit_ticket_balance: self.from_user.fruit_ticket_balance - self.amount
self.to_user.update fruit_ticket_balance: self.to_user.fruit_ticket_balance + self.amount
self.save!
when "shrimpo_deposit"
if self.from_user.fruit_ticket_balance < self.amount
raise "not enough balance"
end
self.from_user.update fruit_ticket_balance: self.from_user.fruit_ticket_balance - self.amount
self.save!
when "shrimpo_deposit_return"
self.to_user.update fruit_ticket_balance: self.to_user.fruit_ticket_balance + self.amount
self.save!
else
raise "invalid transaction_type"
end
Expand Down
6 changes: 5 additions & 1 deletion app/models/post.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Post < ApplicationRecord
after_create :maybe_send_notification

VALID_POSTABLE_TYPES = ['ForumThread', 'ScheduledShow']
VALID_POSTABLE_TYPES = ['ForumThread', 'ScheduledShow', 'Shrimpo', 'ShrimpoEntry']
belongs_to :postable, polymorphic: true, touch: true
belongs_to :user

Expand All @@ -10,6 +10,10 @@ def url
self.postable.url
elsif self.postable_type === "ForumThread"
"https://datafruits.fm/forum/#{self.postable.slug}"
elsif self.postable_type === "Shrimpo"
"https://datafruits.fm/shrimpos/#{self.postable.slug}"
elsif self.postable_type === "ShrimpoEntry"
"https://datafruits.fm/shrimpos/#{self.postable.shrimpo.slug}/entries/#{self.postable.slug}"
end
end

Expand Down
122 changes: 122 additions & 0 deletions app/models/shrimpo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
class Shrimpo < ApplicationRecord
extend FriendlyId
friendly_id :slug_candidates, use: :slugged

include ActionView::Helpers::DateHelper

belongs_to :user
has_many :shrimpo_entries
has_many :posts, as: :postable

has_one_attached :zip
mcfiredrill marked this conversation as resolved.
Show resolved Hide resolved
has_one_attached :cover_art

validates :title, presence: true
validates :emoji, presence: true
validates :rule_pack, presence: true

enum status: [:running, :voting, :completed]

attr_accessor :duration

after_create :queue_end_shrimpo_job

VALID_DURATIONS = [
# minors
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entries to a minor shrimpo are anonymized until the shrimpo is over

entries to a major shrimpo are public even before the voting starts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wow ok didn't even think about that but it makes sense to me. how does one choose one type over the other?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"1 hour",
"2 hours",
"4 hours",
"1 day",
"2 days",
"1 week",
"2 weeks",
# majors
"1 month",
"3 months",
]

def fruit_ticket_deposit_amount
case self.duration.gsub(/about /, '')
when '1 hour'
500
when '2 hours'
750
when '4 hours'
1000
when '1 day'
1500
when '2 days'
1750
when '1 week'
2000
when '1 month'
5000
when '3 months'
7500
end
end

def sorted_entries
self.shrimpo_entries.sort_by(&:created_at)
end

def duration
time_ago_in_words(self.end_at)
end

def duration= d
if VALID_DURATIONS.include? d
# using eval is an extremely *safe* ~good~ thing TO DO >: 3
self.end_at = self.start_at + eval(d.gsub(' ', '.'))
end
end

def slug_candidates
[
[:title],
[:title, :id]
]
end

def save_and_deposit_fruit_tickets!
ActiveRecord::Base.transaction do
transaction = FruitTicketTransaction.new from_user: self.user, amount: self.fruit_ticket_deposit_amount, transaction_type: :shrimpo_deposit
transaction.transact_and_save! && self.save!
end
end

def tally_results!
return unless self.voting? && self.shrimpo_entries.any?

ActiveRecord::Base.transaction do
self.shrimpo_entries.each do |entry|
total_score = entry.shrimpo_votes.sum(:score)
entry.update! total_score: total_score
end

self.shrimpo_entries.sort_by(&:total_score).reverse.each_with_index do |entry, index|
entry.update! ranking: index + 1
end

self.update! ended_at: Time.now
self.completed!
# award xp
self.shrimpo_entries.sort_by(&:ranking).each_with_index do |entry, index|
total_points = 2000 + (25 * self.shrimpo_entries.count)
points = (total_points * ((8 - entry.ranking) * 0.04)).round
ExperiencePointAward.create! user: entry.user, amount: points, award_type: :shrimpo
end
#
# return deposit
if self.shrimpo_entries.count > 2
transaction = FruitTicketTransaction.new to_user: self.user, amount: self.fruit_ticket_deposit_amount, transaction_type: :shrimpo_deposit_return
transaction.transact_and_save!
end
end
end

private
def queue_end_shrimpo_job
EndShrimpoWorker.set(wait_until: self.end_at).perform_later(self.id)
end
end
39 changes: 39 additions & 0 deletions app/models/shrimpo_entry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class ShrimpoEntry < ApplicationRecord
extend FriendlyId
friendly_id :slug_candidates, use: :slugged

belongs_to :shrimpo
belongs_to :user

has_many :shrimpo_votes
has_many :posts, as: :postable

validates :title, presence: true

has_one_attached :audio

def previous_entry
previous, nextious = self.shrimpo.sorted_entries.split(self)
if previous.any?
return previous.last
end
end

def next_entry
previous, nextious = self.shrimpo.sorted_entries.split(self)
if nextious.any?
return nextious.first
end
end

def username
self.user.username
end

def slug_candidates
[
[:title, :username],
[:title, :username, :id],
]
end
end
8 changes: 8 additions & 0 deletions app/models/shrimpo_vote.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class ShrimpoVote < ApplicationRecord
belongs_to :shrimpo_entry
belongs_to :user

validates :score, numericality: { in: 1..6 }

# TODO validate not voting on own entry
end
2 changes: 2 additions & 0 deletions app/models/shrimpo_voting_category.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ShrimpoVotingCategory < ApplicationRecord
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this or maybe we'll use it later IDK yet

end
51 changes: 51 additions & 0 deletions app/serializers/shrimpo_entry_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class ShrimpoEntrySerializer < ActiveModel::Serializer
attributes :title, :audio_file_url, :username, :user_avatar, :slug, :user_role, :cdn_url, :shrimpo_emoji, :shrimpo_slug, :created_at, :previous_shrimpo_entry_slug, :next_shrimpo_entry_slug, :total_score, :ranking
belongs_to :shrimpo
has_many :shrimpo_votes, embed: :ids, key: :shrimpo_votes, embed_in_root: true, each_serializer: ShrimpoVoteSerializer
has_many :posts, embed: :ids, key: :posts, embed_in_root: true, each_serializer: PostSerializer

def previous_shrimpo_entry_slug
if object.previous_entry.present?
object.previous_entry.slug
end
end

def next_shrimpo_entry_slug
if object.next_entry.present?
object.next_entry.slug
end
end

def shrimpo_slug
object.shrimpo.slug
end

def shrimpo_emoji
object.shrimpo.emoji
end

def audio_file_url
end

def cdn_url
if object.audio.present?
if ::Rails.env != "production"
::Rails.application.routes.url_helpers.rails_blob_path(object.audio, only_path: true, disposition: 'attachment')
else
object.audio.url
end
end
end

def user_role
object.user.role
end

def username
object.user.username
end

def user_avatar
CGI.unescape(object.user.image.url(:thumb))
end
end
Loading
Loading