diff --git a/api/resolvers/sub.js b/api/resolvers/sub.js
index ee34e733..19f73581 100644
--- a/api/resolvers/sub.js
+++ b/api/resolvers/sub.js
@@ -315,6 +315,60 @@ export default {
notifyTerritoryTransfer({ models, sub, to: user })
return updatedSub
+ },
+ unarchiveTerritory: async (parent, { hash, hmac, ...data }, { me, models, lnd }) => {
+ if (!me) {
+ throw new GraphQLError('you must be logged in', { extensions: { code: 'UNAUTHENTICATED' } })
+ }
+
+ const { name } = data
+
+ await ssValidate(territorySchema, data, { models, me, sub: { name } })
+
+ const oldSub = await models.sub.findUnique({ where: { name } })
+ if (!oldSub) {
+ throw new GraphQLError('sub not found', { extensions: { code: 'BAD_INPUT' } })
+ }
+ if (oldSub.status !== 'STOPPED') {
+ throw new GraphQLError('sub is not archived', { extensions: { code: 'BAD_INPUT' } })
+ }
+ if (oldSub.billingType === 'ONCE') {
+ // sanity check. this should never happen but leaving this comment here
+ // to stop error propagation just in case and document that this should never happen.
+ // #defensivecode
+ throw new GraphQLError('sub should not be archived', { extensions: { code: 'BAD_INPUT' } })
+ }
+
+ const billingCost = TERRITORY_PERIOD_COST(data.billingType)
+ const billPaidUntil = nextBilling(new Date(), data.billingType)
+ const cost = BigInt(1000) * BigInt(billingCost)
+ const newSub = { ...data, billPaidUntil, billingCost, userId: me.id, status: 'ACTIVE' }
+
+ await serializeInvoicable([
+ models.user.update({
+ where: {
+ id: me.id
+ },
+ data: {
+ msats: {
+ decrement: cost
+ }
+ }
+ }),
+ models.subAct.create({
+ data: {
+ subName: name,
+ userId: me.id,
+ msats: cost,
+ type: 'BILLING'
+ }
+ }),
+ models.sub.update({ where: { name }, data: newSub }),
+ oldSub.userId !== me.id && models.territoryTransfer.create({ data: { subName: name, oldUserId: oldSub.userId, newUserId: me.id } })
+ ].filter(q => !!q),
+ { models, lnd, hash, hmac, me, enforceFee: billingCost })
+
+ if (oldSub.userId !== me.id) notifyTerritoryTransfer({ models, sub: newSub, to: me.id })
}
},
Sub: {
diff --git a/api/typeDefs/sub.js b/api/typeDefs/sub.js
index 806f139d..3de01720 100644
--- a/api/typeDefs/sub.js
+++ b/api/typeDefs/sub.js
@@ -23,6 +23,10 @@ export default gql`
toggleMuteSub(name: String!): Boolean!
toggleSubSubscription(name: String!): Boolean!
transferTerritory(subName: String!, userName: String!): Sub
+ unarchiveTerritory(name: String!, desc: String, baseCost: Int!,
+ postTypes: [String!]!, allowFreebies: Boolean!,
+ billingType: String!, billingAutoRenew: Boolean!,
+ moderated: Boolean!, hash: String, hmac: String, nsfw: Boolean!): Sub
}
type Sub {
diff --git a/components/form.js b/components/form.js
index 7abad582..c9b2915d 100644
--- a/components/form.js
+++ b/components/form.js
@@ -403,7 +403,7 @@ function FormGroup ({ className, label, children }) {
}
function InputInner ({
- prepend, append, hint, showValid, onChange, onBlur, overrideValue, appendValue,
+ prepend, append, hint, warn, showValid, onChange, onBlur, overrideValue, appendValue,
innerRef, noForm, clear, onKeyDown, inputGroupClassName, debounce: debounceTime, maxLength,
...props
}) {
@@ -452,7 +452,7 @@ function InputInner ({
// not assume this is invalid
const isNumeric = /^[0-9]+$/.test(draft)
const numericExpected = typeof field.value === 'number'
- helpers.setValue(isNumeric && numericExpected ? parseInt(draft) : draft, false)
+ helpers.setValue(isNumeric && numericExpected ? parseInt(draft) : draft)
onChange && onChange(formik, { target: { value: draft } })
}
}
@@ -518,7 +518,12 @@ function InputInner ({
{hint}
)}
- {maxLength && !(meta.touched && meta.error && invalid) && (
+ {warn && (
+