* Support `is:bookmarked` search option to search my bookmarked items
* Update the worker search module to include `bookmarkedBy: Array<Number>` which
contains the list of user ids which have bookmarked a given item
* Add a trigger on the `Bookmark` DB table to re-index the corresponding item when
a bookmark is added/removed
* Update the Search resolver to check for a `is:bookmarked` query option. If provided,
include it as an option in the search request. This updates search to look for items
which are bookmarked by the current user. By default, this preserves stacker privacy
so you can only search your own bookmarks
* Update the search page UI to show how to invoke searching your own bookmarks
* undo `is:bookmarked` support, add `bookmarks` item in search select
* short circuit return empty payload for anon requesting bookmarks
* remove console.log for debugging
* fix indexing a new item that has yet to be bookmarked
* update db migration to re-index all existing bookmarked items one time
* fix the case where deleting a bookmark doesn't trigger a new index of items
explictly specify a `updatedAt` value when deleting a bookmark, to ensure that
deleting a bookmark results in a new indexed version of the bookmarked item
* update search indexer to use the latest of all three choices for the latest version
* give bookmark index jobs longer expiration
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
* Also log autowithdrawal routing errors
* Only log autowithdrawal success in worker
* Use WalletType for WalletLog.wallet
* Fix autowithdrawal success message
* Infer walletName from walletType in upsertWallet
* Merge serializeInvoiceable with serialize
* Rename to verifyPayment
We already have a function named checkInvoice in the worker which can be confusing.
Also, we don't need to export this function.
* Use crypto.timingSafeEqual
* Fix missing unwrap for item creation and update
* Merge serializeInvoiceable with serialize
* Rename to verifyPayment
We already have a function named checkInvoice in the worker which can be confusing.
Also, we don't need to export this function.
* Use crypto.timingSafeEqual
* first pass of a mute mgmt page, ported from subscription mgmt page pr
* adjust error message for mutes
* muted users -> muted stackers
* fix typo in component name
* first pass of a subscription management page under settings
* add tabs to settings ui
* NymActionDropdown
* update Apollo InMemoryCache to merge paginated list of my subscribed users
* various updates
* switch from UsersNullable to Users
* bake the nym action dropdwon into the user component
* add back fields to the user query
* `meSubscriptionPosts`, `meSubscriptionComments`, `meMute`
* Refetch my subscribed users when a user subscription is changed
* update user list to hide stats in the subscribed list users
* update my sub'd users fragment to remove unnecessary user fields
* memoize subscribe user context provider value to avoid re-renders
* use inner join instead of left join
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* throw error when unauthenticated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* nwc wallet logs
* persist logs in IndexedDB
* Potential fix for empty error message
* load logs limited to 5m ago from IDB
* load logs from past via query param
* Add 5m, 1h, 6h links for earlier logs
* Show end of log
* Clamp to logStart
* Add log.module.css
* Remove TODO about persistence
* Use table for logs
* <table> fixes bad format with fixed width and message overflow into start of next row
* also using ---start of log--- instead of ---end of log--- now
* removed time string in header nav
* Rename .header to .logNav
* Simply load all logs and remove navigation
I realized the code for navigation was most likely premature optimization which even resulted in worse UX:
Using the buttons to load logs from 5m, 1h, 6h ago sometimes meant that nothing happened at all since there were no logs from 5m, 1h, 6h ago.
That's why I added a time string as "start of logs" so it's at least visible that it changed but that looked bad so I removed it.
But all of this was not necessary: I can simply load all logs at once and then the user can scroll around however they like.
I was worried that it would be bad for performance to load all logs at once since we might store a lot of logs but as mentioned, that's probably premature optimization.
WHEN a lot of logs are stored AND this becomes a problem (What problem even? Slow page load?), THEN we can think about this.
If page load ever becomes slow because of loading logs, we could probably simply not load the logs at page load but only when /wallet/logs is visited.
But for now, this works fine.
* Add follow checkbox
* Create WalletLogs component
* Embed wallet logs
* Remove test error
* Fix level padding
* Add LNbits logs
* Add logs for attaching LND and lnAddr
* Use err.message || err.toString?.() consistently
* Autowithdrawal logs
* Use details from LND error
* Don't log test invoice individually
* Also refetch logs on error
* Remove obsolete and annoying toasts
* Replace scrollIntoView with scroll
* Use constant embedded max-height
* Fix missing width: 100% for embedded logs
* Show full payment hash and preimage in logs
* Also parse details from LND errors on autowithdrawal failures
* Remove TODO
* Fix accidental removal of wss:// check
* Fix alignment of start marker and show empty if empty
* Fix sendPayment loop
* Split context in two
* first pass of disallowing certain APIs with API keys
Disallow the following APIs:
* item.act (zap)
* create withdrawal
* unlink auth method
* link unverified email
* disallow creating lnauths via API key to stop the flow of linking via lnauth
* undo the limitation on donating to rewards
* revert the assertion on createAuth
* assert no api key on createWithdrawal and sendToLNAddr
* incorporate PR feedback by adding API Key negative assertion to more mutations:
* `createInvite`
* `createAuth`
* `upsertWalletLND` by way of `upsertWallet`
* `upsertWalletLNAddr` by way of `upsertWallet`
* Add top cowboys, stackers, and spenders to newsletter
* Rearrange to match the issue title
* fix top spenders `by` variable
* Update user resolver for top users `spending` `by` value
* wrap in try catch to not have errors break the script execution
return the array as defined whenever an error occurs
* Handle archived territories in territory form
* Use dedicated mutation
* Add sanity check for eternal territories
* Fix fields and cost ignored
* Remove no longer needed manual validation in upsertSub
* Remove founder check
* Always check if sub is archived
Using { abortEarly: false } now since previously, if no description was not given, we wouldn't detect if the sub was archived since validation would abort on empty descriptions.
Only on submission all fields would get validated but since we ignore archived errors during submission, the user would never see that the sub is archived before submission
+ the wrong mutation would run if archived is not already true before submission.
Hence, we need to validate all fields always.
There is currently still a bug where the validation does not immediately run but maybe this can be fixed by simply using validateImmediately on the Formik component.
* Fix archived warning not shown after first render
* Only create transfers if owner actually changes
* Reuse helper functions in lib/territory.js
* Rename var to editing
* Use onChange instead of validation override
* Run same validation on server for unarchiving
* Fix 'territory archived' shown during edits
* Use && instead of ternary operator for conditional query
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* Generate API key in settings
* Check x-api-key for GraphQL API requests
* Don't fallback to cookie if x-api-key header was provided
* Select all session fields
* Fix error if API key not found
* Fix style in settings via form-label className
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* Ignore if sub belongs to user during existence check
* Remove code no longer needed
* Fix territory edit
Territory edits were broken because validation failed for existing territories and if you edit an territory, it obviously already exists.
This commit fixes this by ignoring the territory that we're currently editing.
* Fix existence check using stale cache
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* Don't hide self in top even if hidden
* Also don't hide self in top cowboys
* only use anon icon for anon stuff
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
* Allow founders to transfer territories
* Log territory transfers in new AuditLog table
* Add territory transfer notifications
* Use polymorphic AuditEvent table
* Add setting for territory transfer notifications
* Add push notification
* Rename label from user to stacker
* More space between cancel and confirm button
* Remove AuditEvent table
The audit table is not necessary for territory transfers and only adds complexity and unrelated discussion to this PR.
Thinking about a future-proof schema for territory transfers and how/what to audit at the same time made my head spin.
Some thoughts I had:
1. Maybe using polymorphism for an audit log / audit events is not a good idea
Using polymorphism as is currently used in the code base (user wallets) means that every generic event must map to exactly one specialized event.
Is this a good requirement/assumption? It already didn't work well for naive auditing of territory transfers since we want events to be indexable by user (no array column) so every event needs to point to a single user but a territory transfer involves multiple users.
This made me wonder: Do we even need a table? Maybe the audit log for a user can be implemented using a view? This would also mean no data denormalization.
2. What to audit and how and why?
Most actions are already tracked in some way by necessity: zaps, items, mutes, payments, ...
In that case: what is the benefit of tracking these things individually in a separate table?
Denormalize simply for convenience or performance? Why no view (see previous point)? Use case needs to be more clearly defined before speccing out a schema.
* Fix territory transfer notification id conflict
* Use include instead of two separate queries
* Drop territory transfer setting
* Remove trigger usage
* Prevent transfers to yourself
* show placeholder for hidden stackers in top
* top rewardability views
* make territory revenue idependent job
* monthly rewards and leaderboard on rewards pages
* fix earn reschedule
* add query for rewards leaderboard
* reduce likelihood of rewards racing with views
* fix earn and refine values views
* Territory notifications
* Migrate old setting to new table
* Auto subscribe founders to their territories on creation
* Fix (un)subscribe not shown to founder
* Rename to toggleSubSubscription
* Fix inconsistency between toggleSubSubscription and toggleMuteSub
* Add dedicated button in header for following territories
* Don't drop noteTerritoryPosts column
* Fix db dip in Sub.meSubscription resolver
* Move territory subscribe to new territory context menu
* Decrease space between share icon and mute button
* Fix eslint
* add nterritories field to User
* add userSubs query
* show territories tab on user profiles
hide the tab if user has 0 territories, except when the
viewer navigated directly to the user's territories page
* add USER_WITH_SUBS query for user territories page
* add user territories page
* add poll expires at column to Item table
* update upsertPoll mutation for pollExpiresAt param
* use pollExpiresAt to show time left for poll
* correctly pluralize days for timeLeft
* correctly update pollExpiresAt when item is updated to remove poll expiration
* add DateTimePicker and DateTimeInput components to select datetimes
* update pollExpiresAt to be nullable and more than 1 day in the future
* hide time left text if poll has no expiration
* initialize pollExpiresAt with current value or default of 25 hours in the future
we add a one hour time buffer so that the user doesn't get a validation error
for pollExpiresAt if they post their poll within an hour from creation. there's
still a chance they'll hit the validation error but they should see the error
message toast
* add DateTimeInput into the options part of the poll form
add right padding to make room for the "clear" button.
allow field to be cleared (i.e. null pollExpiresAt) to allow
non-ending polls.
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* auto canceling bolt11s from lnd when auto dropped from DB
* auto canceling bolt11s from lnd when auto dropped from DB
* removed semicolon for lint
* changed cancleHodlInvoic to deletePayment function
* updated code to account for failed LND deletes
* linter fixes
* updated to only remove hashes and bolt11's from model when successfully deleted from LND
* updated to revert unsuccessful deletes from LND and add those values back into the db
* linter fix and renaming for clarity
* updated WITH query
* added if statement to account for invoices not returning from db
* fixed linter
* reverted docker-compose.yml
* made it dry
* made it dry
* added a comment because the query might be confusing
* made query moar dry
* Query formatting
* Fix query returns number of rows instead of rows
* updated to
* fixed linter
* removed lnbits dir
* removed gitignore and docker-compose.yml from pr
* added deleting from LND in wallet resolver
* linter + added missing import
* fixed merge conflict
* refine invoice deletion
---------
Co-authored-by: ekzyis <ek@stacker.news>
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
* add subViewGroup function to create view to read sub stats from
* add topSubs resolver to graphql query
* add TOP_SUBS query fragment
* add SUB_SORTS for top territory sorting
* add custom cache policy for topSubs
* add territories to top header select
* add top territories page
* add db views for sub stats
* configure sub_stats views to refresh by worker
* filter rows with empty subName
* update msats_spent calculation to include all ItemAct in sub
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* add nsfw column to sub
* add nsfw boolean to territorySchema
* save nsfw value in upsertSub mutation
* return nsfw value from Sub query for correct value in edit territory form
* add nsfw checkbox to territory form
* add nsfw badge to territory header
* add nsfwMode to user
* show nsfw badge next to item territory
* exclude nsfw sub from items query
* show nsfw mode checkbox on settings page
* fix nsfw badge formatting
* separate user from current, signed in user
* update relationClause to join with sub table
* refactor to simplify hide nsfw sql
* filter nsfw items when viewing user items
* hide nsfw posts for logged out users
* filter nsfw subs based on user preference
* show nsfw sub name if logged out user is viewing the page
* show current sub at the top of the list instead of bottom
* always join item with sub to check nsfw
* check for sub presence before showing nsfw badge on item
* skip manually adding sub to select if sub is null
* fix relationClause to join with root item
* move moderation and nsfw into accordion
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* improves ux for url only searches
* updates with sn nym
* add back original implementation when query has more than url: filter
* eliminates use of wildcards
* adds docs for testing search in a way that more closely resembles prod
* fixes lint issues
---------
Co-authored-by: utanapishtim <utnapishtim.utanapishtim@gmail.com>
It looks like a regression was introduced at some point, because
the `uri` that's compared against the `whitelist` is a regular
expression and not the url hostname + pathname as it was originally
written.
This brings back the original behavior of comparing the whitelist
against the hostname + pathname
* Use parallel invoice subscriptions
* Fix missing idempotency
* Log error
* Use cursor for invoice subscription
* Subscribe to outgoing payments for withdrawals
* Add TODO comments regarding migration to LND subscriptions
* Also use isPoll variable in checkInvoice
* Queue status check of pending withdrawals
* Use for loop to check pending withdrawals
* Reconnect to LND gRPC API on error
* Fix hash modified of applied migrations
* Separate wallet code from worker index
* refactor subscription code some more
* remove unnecessary subWrapper abstraction
* move all wallet related code into worker/wallet.js such that only a single import is needed in worker/index.js
* Migrate from polling to LND subscriptions
* Remove unnecessary reconnect code
* Add FIXME
* Add listener for HODL invoice updates
* Remove obsolete comment
* Update README
* Add job to cancel hodl invoice if expired
* Fix missing else
* small bug fixes and readability enhancements
* refine and add periodic redundant deposit/withdrawal checks
---------
Co-authored-by: ekzyis <ek@stacker.news>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
* Add nostr event id field to items
* crosspost-item
* crosspost old items, update with nEventId
* Updating noteId encoding, cleaning up a little
* Fixing item-info condition, cleaning up
* Linting
* Spacing nit
* Add createdAt variable back
* Change instances of eventId to noteId
* Adding upsertNoteId mutation
* Cleaning up updateItem, using toasts to communivate success/failure in crosspost-item
* Linting
* Fix type
* Move crosspost to share button, make sure only OP can crosspost
* Lint
* Simplify conditions
* user might have no nostr extension installed
Co-authored-by: ekzyis <27162016+ekzyis@users.noreply.github.com>
* change upsertNoteId to updateNoteID for resolver and mutations, change isOp to mine, remove unused noteId params
* Use nostr.com for linking out with noteId
* lint
* add noopener to window.open call
* Simplify condition, throw GraphQLError
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
Co-authored-by: ekzyis <27162016+ekzyis@users.noreply.github.com>
* Toast on successful delete bot directive
* refactor duplicate code into a reusable function
* restore empty spacing lines to clean up the diff
* perf optimization, only query for deleteScheduledAt for your own items
* Issue a warning toast if the delete bot was mentioned but the item was not scheduled for deletion
* use bs-secondary color for warning
---------
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* add custom range option to top items page
* add custom range option to profile page
* add date filter option to chart pages
* cleanup
* fix x-axis date labels
* date picker improvements
* enhancements to custom date selection
* remove unneeded condition
---------
Co-authored-by: rleed <rleed1@pm.me>
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
* Add icon to add images
* Open file explorer to select image
* Upload images to S3 on selection
* Show uploaded images below text input
* Link and remove image
* Fetch unsubmitted images from database
* Mark S3 images as submitted in imgproxy job
* Add margin-top
* Mark images as submitted on client after successful mutation
* Also delete objects in S3
* Allow items to have multiple uploads linked
* Overwrite old avatar
* Add fees for presigned URLs
* Use Github style upload
* removed upfront fees
* removed images provider since we no longer need to keep track of unsubmitted images on the client
* removed User.images resolver
* removed deleteImage mutation
* use Github style upload where it shows ![Uploading <filename>...]() first and then replaces that with ![<filename>](<url>) after successful upload
* Add Upload.paid boolean column
One item can have multiple images linked to it, but an image can also be used in multiple items (many-to-many relation).
Since we don't really care to which item an image is linked and vice versa, we just use a boolean column to mark if an image was already paid for.
This makes fee calculation easier since no JOINs are required.
* Add image fees during item creation/update
* we calculate image fees during item creation and update now
* function imageFees returns queries which deduct fees from user and mark images as paid + fees
* queries need to be run inside same transaction as item creation/update
* Allow anons to get presigned URLs
* Add comments regarding avatar upload
* Use megabytes in error message
* Remove unnecessary avatar check during image fees calculation
* Show image fees in frontend
* Also update image fees on blur
This makes sure that the images fees reflect the current state. For example, if an image was removed.
We could also add debounced requests.
* Show amount of unpaid images in receipt
* Fix fees in sats deducted from msats
* Fix algebraic order of fees
Spam fees must come immediately after the base fee since it multiplies the base fee.
* Fix image fees in edit receipt
* Fix stale fees shown
If we pay for an image and then want to edit the comment, the cache might return stale date; suggesting we didn't pay for the existing image yet.
* Add 0 base fee in edit receipt
* Remove 's' from 'image fees' in receipts
* Remove unnecessary async
* Remove 'Uploading <name>...' from text input on error
* Support upload of multiple files at once
* Add schedule to delete unused images
* Fix image fee display in receipts
* Use Drag and Drop API for image upload
* Remove dragOver style on drop
* Increase max upload size to 10MB to allow HQ camera pictures
* Fix free upload quota
* Fix stale image fees served
* Fix bad image fee return statements
* Fix multiplication with feesPerImage
* Fix NULL returned for size24h, sizeNow
* Remove unnecessary text field in query
* refactor: Unify <ImageUpload> and <Upload> component
* Add avatar cache busting using random query param
* Calculate image fee info in postgres function
* we now calculate image fee info in a postgres function which is much cleaner
* we use this function inside `create_item` and `update_item`: image fees are now deducted in the same transaction as creating/updating the item!
* reversed changes in `serializeInvoiceable`
* Fix line break in receipt
* Update upload limits
* Add comment about `e.target.value = null`
* Use debounce instead of onBlur to update image fees info
* Fix invoice amount
* Refactor avatar upload control flow
* Update image fees in onChange
* Fix rescheduling of other jobs
* also update schedule from every minute to every hour
* Add image fees in calling context
* keep item ids on uploads
* Fix incompatible onSubmit signature
* Revert "keep item ids on uploads"
This reverts commit 4688962abc.
* many2many item uploads
* pretty subdomain for images
* handle upload conditions for profile images and job logos
---------
Co-authored-by: ekzyis <ek@ekzyis.com>
Co-authored-by: ekzyis <ek@stacker.news>