Skip to content
Snippets Groups Projects

Resolve "subscription ended on submit"

Merged Dominik Seeger requested to merge 139-subscription-ended-on-submit into master
@@ -9,24 +9,20 @@ import { getStoreBuilder, BareActionContext } from 'vuex-typex'
export interface SubscriptionsState {
subscriptions: {[pk: string]: Subscription}
assignmentQueue: Array<Assignment>
activeSubscriptionPk: string
currentAssignment?: Assignment
loading: boolean
}
function initialState (): SubscriptionsState {
return {
subscriptions: {},
assignmentQueue: [],
activeSubscriptionPk: '',
currentAssignment: undefined,
loading: false
}
}
const mb = getStoreBuilder<RootState>().module('Subscriptions', initialState())
const MAX_NUMBER_OF_ASSIGNMENTS = 2
const stateGetter = mb.state()
const availableTypesGetter = mb.read(function availableTypes (state, getters) {
@@ -36,6 +32,7 @@ const availableTypesGetter = mb.read(function availableTypes (state, getters) {
}
return types
})
const availableStagesGetter = mb.read(function availableStages (state, getters) {
let stages = [Subscription.FeedbackStageEnum.Creation, Subscription.FeedbackStageEnum.Validation]
if (Authentication.isReviewer) {
@@ -43,6 +40,7 @@ const availableStagesGetter = mb.read(function availableStages (state, getters)
}
return stages
})
const availableStagesReadableGetter = mb.read(function availableStagesReadable (state, getters) {
let stages = ['initial', 'validate']
if (Authentication.isReviewer) {
@@ -50,15 +48,23 @@ const availableStagesReadableGetter = mb.read(function availableStagesReadable (
}
return stages
})
const availableSubmissionTypeQueryKeysGetter = mb.read(function availableSubmissionTypeQueryKeys (state, getters, rootState) {
return Object.values(rootState.submissionTypes).map((subType: any) => subType.pk)
})
const availableExamTypeQueryKeysGetter = mb.read(function availableExamTypeQueryKeys (state, getters, rootState) {
return Object.values(rootState.examTypes).map((examType: any) => examType.pk)
})
const activeSubscriptionGetter = mb.read(function activeSubscription (state) {
return state.subscriptions[state.activeSubscriptionPk]
if (state.currentAssignment && state.currentAssignment.subscription) {
return state.subscriptions[state.currentAssignment.subscription]
}
return undefined
})
const resolveSubscriptionKeyToNameGetter = mb.read(function resolveSubscriptionKeyToName (state, getters, rootState) {
return (subscription: {queryType: Subscription.QueryTypeEnum, queryKey: string}) => {
switch (subscription.queryType) {
@@ -127,21 +133,15 @@ function SET_SUBSCRIPTIONS (state: SubscriptionsState, subscriptions: Array<Subs
return acc
}, {})
}
function SET_SUBSCRIPTION (state: SubscriptionsState, subscription: Subscription): void {
Vue.set(state.subscriptions, subscription.pk, subscription)
}
function SET_ACTIVE_SUBSCRIPTION_PK (state: SubscriptionsState, subscriptionPk: string): void {
state.activeSubscriptionPk = subscriptionPk
}
function SET_ASSIGNMENT_QUEUE (state: SubscriptionsState, queue: Array<Assignment>): void {
state.assignmentQueue = queue
}
function ADD_ASSIGNMENT_TO_QUEUE (state: SubscriptionsState, assignment: Assignment): void {
state.assignmentQueue.push(assignment)
}
function POP_ASSIGNMENT_FROM_QUEUE (state: SubscriptionsState): void {
state.assignmentQueue.shift()
function SET_CURRENT_ASSIGNMENT (state: SubscriptionsState, assignment?: Assignment): void {
state.currentAssignment = assignment
}
function RESET_STATE (state: SubscriptionsState): void {
Object.assign(state, initialState())
subscribeToAll.reset()
@@ -162,34 +162,43 @@ async function subscribeTo (
Subscriptions.SET_SUBSCRIPTION(subscription)
return subscription
}
async function getSubscriptions () {
const subscriptions = await api.fetchSubscriptions()
Subscriptions.SET_SUBSCRIPTIONS(subscriptions)
return subscriptions
}
/**
* Creates as many assignments as needed to reach MAX_NUMBER_OF_ASSIGNMENTS
* @param numOfAssignments Use to override default behaviour of
* creating MAX_NUMBER_OF_ASSIGNMENTS - assignmentQueue.length assignments
*/
async function getAssignmentsForActiveSubscription
(context: BareActionContext<SubscriptionsState, RootState>, numOfAssignments: number):
Promise<Promise<Assignment>[]> {
numOfAssignments = numOfAssignments || MAX_NUMBER_OF_ASSIGNMENTS - context.state.assignmentQueue.length
let assignmentsPromises = []
for (let i = 0; i < numOfAssignments; i++) {
assignmentsPromises.push(api.createAssignment({ subscription: Subscriptions.activeSubscription }))
async function changeToSubscription({state}: BareActionContext<SubscriptionsState, RootState>, subscriptionPk: string) {
const currAssignment = state.currentAssignment
if (currAssignment && currAssignment.subscription == subscriptionPk) {
return
}
return assignmentsPromises
if (currAssignment) {
await api.deleteAssignment({assignment: currAssignment})
}
const newAssignment = await api.createAssignment({subscriptionPk})
Subscriptions.SET_CURRENT_ASSIGNMENT(newAssignment)
}
async function deleteAssignment
(context: BareActionContext<SubscriptionsState, RootState>, assignment: Assignment) {
return api.deleteAssignment({ assignment })
async function createNextAssignment() {
const activeSubscription = Subscriptions.activeSubscription
if (!activeSubscription) {
throw new Error("There must be an active Subscription before calling createNextAssignment")
}
const newAssignment = await api.createAssignment({subscription: activeSubscription})
Subscriptions.SET_CURRENT_ASSIGNMENT(newAssignment)
}
async function cleanAssignmentsFromSubscriptions
({ state }: BareActionContext<SubscriptionsState, RootState>, excludeActive = true) {
Object.values(state.subscriptions).forEach(subscription => {
if (!excludeActive || subscription.pk !== state.activeSubscriptionPk) {
if (!excludeActive ||
!Subscriptions.activeSubscription ||
subscription.pk !== Subscriptions.activeSubscription.pk) {
if (subscription.assignments) {
subscription.assignments.forEach(assignment => {
api.deleteAssignment({ assignment })
@@ -198,48 +207,26 @@ async function cleanAssignmentsFromSubscriptions
}
})
}
async function skipAssignment ({ state }: BareActionContext<SubscriptionsState, RootState>) {
Subscriptions.deleteAssignment(state.assignmentQueue[0])
.then(() => {
// pass numOfAssignments = 1 to create 1 new assignment although maybe two are already in the queue,
// this is needed because otherwise the current assignment in the comp. might be unknown for a period
// which will result get incorrectly interpreted as a an ended subscription
return Subscriptions.getAssignmentsForActiveSubscription(1)
}).then(([promise]) => {
promise.then((assignment: Assignment) => {
Subscriptions.ADD_ASSIGNMENT_TO_QUEUE(assignment)
Subscriptions.POP_ASSIGNMENT_FROM_QUEUE()
})
})
}
async function deleteActiveAssignments ({ state }: BareActionContext<SubscriptionsState, RootState>) {
Promise.all(state.assignmentQueue.map(assignment => {
Subscriptions.deleteAssignment(assignment)
}))
}
async function changeActiveSubscription ({ state }: BareActionContext<SubscriptionsState, RootState>, subscriptionPk = '') {
if (subscriptionPk === state.activeSubscriptionPk) {
return
}
await Subscriptions.deleteActiveAssignments()
Subscriptions.SET_ACTIVE_SUBSCRIPTION_PK(subscriptionPk)
let assignmentsPromises = await Subscriptions.getAssignmentsForActiveSubscription(MAX_NUMBER_OF_ASSIGNMENTS)
let createdAssignments = []
// TODO refactor this since it's very bad to await promises in for loops
for (let promise of assignmentsPromises) {
try {
createdAssignments.push(await promise)
} catch (_) {}
if (!state.currentAssignment || !state.currentAssignment.subscription) {
throw new Error("skipAssignment can only be called with active assignment")
}
Subscriptions.SET_ASSIGNMENT_QUEUE(createdAssignments)
const newAssignment = await api.createAssignment({subscriptionPk: state.currentAssignment.subscription})
await api.deleteAssignment({assignment: state.currentAssignment })
Subscriptions.SET_CURRENT_ASSIGNMENT(newAssignment)
}
async function removeActiveSubscription () {
await Subscriptions.deleteActiveAssignments()
Subscriptions.SET_ASSIGNMENT_QUEUE([])
Subscriptions.SET_ACTIVE_SUBSCRIPTION_PK('')
async function deleteCurrentAssignment ({ state }: BareActionContext<SubscriptionsState, RootState>) {
if (!state.currentAssignment) {
throw new Error("No active assignment to delete")
}
await api.deleteAssignment({assignment: state.currentAssignment})
Subscriptions.SET_CURRENT_ASSIGNMENT(undefined)
}
// TODO use enums here
async function subscribeToType
(context: BareActionContext<SubscriptionsState, RootState>, type: Subscription.QueryTypeEnum) {
switch (type) {
@@ -268,6 +255,7 @@ async function subscribeToType
break
}
}
const subscribeToAll = once(async () => {
return Promise.all(flatten(Subscriptions.availableTypes.map((type) => {
return Subscriptions.subscribeToType(type)
@@ -287,21 +275,16 @@ export const Subscriptions = {
SET_SUBSCRIPTIONS: mb.commit(SET_SUBSCRIPTIONS),
SET_SUBSCRIPTION: mb.commit(SET_SUBSCRIPTION),
SET_ACTIVE_SUBSCRIPTION_PK: mb.commit(SET_ACTIVE_SUBSCRIPTION_PK),
SET_ASSIGNMENT_QUEUE: mb.commit(SET_ASSIGNMENT_QUEUE),
ADD_ASSIGNMENT_TO_QUEUE: mb.commit(ADD_ASSIGNMENT_TO_QUEUE),
POP_ASSIGNMENT_FROM_QUEUE: mb.commit(POP_ASSIGNMENT_FROM_QUEUE),
SET_CURRENT_ASSIGNMENT: mb.commit(SET_CURRENT_ASSIGNMENT),
RESET_STATE: mb.commit(RESET_STATE),
subscribeTo: mb.dispatch(subscribeTo),
getSubscriptions: mb.dispatch(getSubscriptions),
getAssignmentsForActiveSubscription: mb.dispatch(getAssignmentsForActiveSubscription),
deleteAssignment: mb.dispatch(deleteAssignment),
cleanAssignmentsFromSubscriptions: mb.dispatch(cleanAssignmentsFromSubscriptions),
changeToSubscription: mb.dispatch(changeToSubscription),
createNextAssignment: mb.dispatch(createNextAssignment),
skipAssignment: mb.dispatch(skipAssignment),
deleteActiveAssignments: mb.dispatch(deleteActiveAssignments),
changeActiveSubscription: mb.dispatch(changeActiveSubscription),
removeActiveSubscription: mb.dispatch(removeActiveSubscription),
deleteCurrentAssignment: mb.dispatch(deleteCurrentAssignment),
subscribeToType: mb.dispatch(subscribeToType),
subscribeToAll: mb.dispatch(subscribeToAll, 'subscribeToAll')
}
Loading