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

feat: Add keys/strings as a metric #2942

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .run/Frontend localhost.run.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Frontend localhost" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/webapp/package.json" />
<package-json value="$PROJECT_DIR$/public/webapp/package.json" />
<command value="run" />
<scripts>
<script value="start" />
Expand All @@ -9,4 +9,4 @@
<envs />
<method v="2" />
</configuration>
</component>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package io.tolgee.api.v2.controllers.organization
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import io.tolgee.component.mtBucketSizeProvider.PayAsYouGoCreditsProvider
import io.tolgee.component.translationsLimitProvider.TranslationsLimitProvider
import io.tolgee.component.translationsLimitProvider.LimitsProvider
import io.tolgee.configuration.tolgee.TolgeeProperties
import io.tolgee.constants.Message
import io.tolgee.dtos.queryResults.organization.OrganizationView
Expand Down Expand Up @@ -89,7 +89,7 @@ class OrganizationController(
private val imageUploadService: ImageUploadService,
private val mtCreditConsumer: MtCreditsService,
private val organizationStatsService: OrganizationStatsService,
private val translationsLimitProvider: TranslationsLimitProvider,
private val limitsProvider: LimitsProvider,
private val projectService: ProjectService,
private val payAsYouGoCreditsProvider: PayAsYouGoCreditsProvider,
) {
Expand Down Expand Up @@ -259,7 +259,7 @@ class OrganizationController(
@PathVariable("organizationId") organizationId: Long,
@PathVariable("userId") userId: Long,
) {
organizationRoleService.removeUser(organizationId, userId)
organizationRoleService.removeUser(userId, organizationId)
}

@PutMapping("/{id:[0-9]+}/avatar", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
Expand Down Expand Up @@ -311,11 +311,16 @@ class OrganizationController(
): PublicUsageModel {
val organization = organizationService.get(organizationId)
val creditBalances = mtCreditConsumer.getCreditBalances(organization.id)
val currentTranslationSlots = organizationStatsService.getCurrentTranslationSlotCount(organizationId)
val currentTranslationSlots = organizationStatsService.getTranslationSlotCount(organizationId)
val currentPayAsYouGoMtCredits = payAsYouGoCreditsProvider.getUsedPayAsYouGoCredits(organization)
val availablePayAsYouGoMtCredits = payAsYouGoCreditsProvider.getPayAsYouGoAvailableCredits(organization)
val currentTranslations = organizationStatsService.getCurrentTranslationCount(organizationId)
val currentTranslations = organizationStatsService.getTranslationCount(organizationId)
val currentSeats = organizationStatsService.getSeatCountToCountSeats(organizationId)
val currentKeys = organizationStatsService.getKeyCount(organizationId)
val limits = limitsProvider.getLimits(organizationId)

return PublicUsageModel(
isPayAsYouGo = limits.isPayAsYouGo,
organizationId = organizationId,
creditBalance = creditBalances.creditBalance / 100,
includedMtCredits = creditBalances.bucketSize / 100,
Expand All @@ -325,10 +330,23 @@ class OrganizationController(
availablePayAsYouGoMtCredits = availablePayAsYouGoMtCredits,
currentTranslations = currentTranslations,
currentTranslationSlots = currentTranslationSlots,
includedTranslations = translationsLimitProvider.getPlanTranslations(organization),
includedTranslationSlots = translationsLimitProvider.getPlanTranslationSlots(organization),
translationSlotsLimit = translationsLimitProvider.getTranslationSlotsLimit(organization),
translationsLimit = translationsLimitProvider.getTranslationLimit(organization),

includedTranslations = limits.strings.included,
translationsLimit = limits.strings.limit,

includedTranslationSlots = limits.translationSlots.included,
translationSlotsLimit = limits.translationSlots.limit,

includedKeys = limits.keys.included,
keysLimit = limits.keys.limit,

includedSeats = limits.seats.included,
seatsLimit = limits.seats.limit,

currentKeys = currentKeys,
currentSeats = currentSeats,

usedMtCredits = creditBalances.usedCredits / 100,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class ProjectsController(
if (userId == authenticationFacade.authenticatedUser.id) {
throw BadRequestException(Message.CAN_NOT_REVOKE_OWN_PERMISSIONS)
}
permissionService.revoke(projectId, userId)
permissionService.revoke(userId, projectId)
}

@PutMapping(value = ["/{projectId:[0-9]+}/leave"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController

@RestController
@CrossOrigin(origins = ["*"])
@RequestMapping("/v2/auth-provider") // TODO: I should probably use the v2
@RequestMapping("/v2/auth-provider")
@AuthenticationTag
@OpenApiHideFromPublicDocs
class AuthProviderChangeController(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ open class PlanIncludedUsageModel(
var translationSlots: Long = -1L,
var translations: Long = -1L,
var mtCredits: Long = -1L,
var keys: Long = -1L,
) : RepresentationModel<PlanIncludedUsageModel>(), Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ open class PlanPricesModel(
val perThousandMtCredits: BigDecimal? = BigDecimal.ZERO,
val subscriptionMonthly: BigDecimal = BigDecimal.ZERO,
val subscriptionYearly: BigDecimal = BigDecimal.ZERO,
val perThousandKeys: BigDecimal = BigDecimal.ZERO,
) : RepresentationModel<PlanPricesModel>(), Serializable

// TODO: Test it always counts usage, to handle situation when user switches between free plan, strings or key based plans.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import java.io.Serializable
@Suppress("unused")
@Relation(collectionRelation = "plans", itemRelation = "plan")
open class PublicUsageModel(
@Schema(
description = "Whether the current plan is pay-as-you-go of fixed. " +
"For pay-as-you-go plans, the spending limit is the top limit."
)
val isPayAsYouGo: Boolean,
val organizationId: Long,
@Schema(description = "Current balance of standard credits. Standard credits are refilled every month")
val creditBalance: Long,
Expand All @@ -21,6 +26,10 @@ open class PublicUsageModel(
val creditBalanceNextRefillAt: Long,
@Schema(description = "Currently used credits over credits included in plan and extra credits")
val currentPayAsYouGoMtCredits: Long,

@Schema(description = "Currently used credits including credits used over the limit")
val usedMtCredits: Long,

@Schema(
description =
"The maximum amount organization can spend" +
Expand Down Expand Up @@ -57,6 +66,44 @@ open class PublicUsageModel(
"(For pay us you go, the top limit is the spending limit)",
)
val translationsLimit: Long,

@Schema(
description =
"How many keys are included in current subscription plan. " +
"How many keys can organization use without additional costs.",
)
val includedKeys: Long,

@Schema(
description = """How many keys are currently stored by organization""",
)
val currentKeys: Long,

@Schema(
description =
"How many keys can be stored until reaching the limit. " +
"(For pay us you go, the top limit is the spending limit)",
)
val keysLimit: Long,

@Schema(
description =
"How many seats are included in current subscription plan. " +
"How many seats can organization use without additional costs.",
)
val includedSeats: Long,

@Schema(
description = """How seats are currently used by organization""",
)
val currentSeats: Long,

@Schema(
description =
"How many seats can be stored until reaching the limit. " +
"(For pay us you go, the top limit is the spending limit)",
)
val seatsLimit: Long,
) : RepresentationModel<PublicUsageModel>(), Serializable {
@Schema(
deprecated = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class OrganizationRoleCachingTest : AbstractSpringTest() {
@Test
fun `it evicts on remove user`() {
populateCache(testData.pepaOrg.id, testData.pepa.id)
organizationRoleService.removeUser(testData.pepaOrg.id, testData.pepa.id)
organizationRoleService.removeUser(testData.pepa.id, testData.pepaOrg.id)
assertCacheEvicted(testData.pepaOrg.id, testData.pepa.id)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ActivityDatabaseInterceptor : Interceptor, Logging {
propertyNames: Array<out String>?,
types: Array<out Type>?,
): Boolean {
preCommitEventsPublisher.onUpdate(entity)
preCommitEventsPublisher.onUpdate(entity, previousState, propertyNames)
interceptedEventsManager.onFieldModificationsActivity(
entity,
currentState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class PreCommitEventPublisher(private val applicationContext: ApplicationContext
applicationContext.publishEvent(OnEntityPrePersist(this, entity))
}

fun onUpdate(entity: Any?) {
applicationContext.publishEvent(OnEntityPreUpdate(this, entity))
fun onUpdate(entity: Any?, previousState: Array<out Any>?, propertyNames: Array<out String>?) {
applicationContext.publishEvent(OnEntityPreUpdate(this, entity, previousState, propertyNames))
}

fun onDelete(entity: Any?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import io.tolgee.constants.Message
import io.tolgee.exceptions.FormalityNotSupportedException
import io.tolgee.exceptions.LanguageNotSupportedException
import io.tolgee.exceptions.OutOfCreditsException
import io.tolgee.exceptions.PlanTranslationLimitExceeded
import io.tolgee.exceptions.TranslationSpendingLimitExceeded
import io.tolgee.exceptions.limits.PlanTranslationLimitExceeded
import io.tolgee.exceptions.limits.TranslationSpendingLimitExceeded
import io.tolgee.service.key.KeyService
import io.tolgee.service.language.LanguageService
import io.tolgee.service.translation.AutoTranslationService
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.tolgee.component.translationsLimitProvider

import io.tolgee.dtos.UsageLimits
import io.tolgee.model.Organization
import org.springframework.stereotype.Component

@Component
class BaseLimitsProvider : LimitsProvider {
override fun getLimits(organizationId: Long): UsageLimits {
return UsageLimits(
isPayAsYouGo = false,
keys = UsageLimits.Limit(
included = -1,
limit = -1
),
seats = UsageLimits.Limit(
included = -1,
limit = -1
),
strings = UsageLimits.Limit(
included = -1,
limit = -1
),
translationSlots = UsageLimits.Limit(
included = -1,
limit = -1
),
isTrial = false
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.tolgee.component.translationsLimitProvider

import io.tolgee.dtos.UsageLimits

interface LimitsProvider {
fun getLimits(organizationId: Long): UsageLimits
}

This file was deleted.

5 changes: 5 additions & 0 deletions backend/data/src/main/kotlin/io/tolgee/constants/Message.kt
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ enum class Message {
CANNOT_UPDATE_WITHOUT_MODIFICATION,
CURRENT_SUBSCRIPTION_IS_NOT_TRIALING,
SORTING_AND_PAGING_IS_NOT_SUPPORTED_WHEN_USING_CURSOR,
STRINGS_METRIC_ARE_NOT_SUPPORTED,
KEYS_SEATS_METRIC_ARE_NOT_SUPPORTED_FOR_SLOTS_FIXED_TYPE,
PLAN_KEY_LIMIT_EXCEEDED,
KEYS_SPENDING_LIMIT_EXCEEDED,
PLAN_SEAT_LIMIT_EXCEEDED,
;

val code: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@ interface AdditionalTestDataSaver {
fun save(builder: TestDataBuilder)

fun clean(builder: TestDataBuilder)

fun beforeSave(builder: TestDataBuilder) {}

fun afterSave(builder: TestDataBuilder) {}

fun beforeClean(builder: TestDataBuilder) {}

fun afterClean(builder: TestDataBuilder) {}
}
Loading