🐛 Bug fixes of risk detection
💄 Optimized UI
			
			
This commit is contained in:
		
							
								
								
									
										11
									
								
								.idea/workspace.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								.idea/workspace.xml
									
									
									
										generated
									
									
									
								
							@@ -4,10 +4,12 @@
 | 
			
		||||
    <option name="autoReloadType" value="ALL" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ChangeListManager">
 | 
			
		||||
    <list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":sparkles: Bug fixes">
 | 
			
		||||
    <list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":sparkles: Batch mark notify as read API">
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/server/notifications_api.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/notifications_api.go" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/server/startup.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/startup.go" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/server/auth_api.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/auth_api.go" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/services/ticket.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/services/ticket.go" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/views/partials/header.gohtml" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/views/partials/header.gohtml" afterDir="false" />
 | 
			
		||||
      <change beforePath="$PROJECT_DIR$/pkg/views/users/personalize.gohtml" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/views/users/personalize.gohtml" afterDir="false" />
 | 
			
		||||
    </list>
 | 
			
		||||
    <option name="SHOW_DIALOG" value="false" />
 | 
			
		||||
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
 | 
			
		||||
@@ -140,7 +142,8 @@
 | 
			
		||||
    <MESSAGE value=":lipstick: Fix ui design" />
 | 
			
		||||
    <MESSAGE value=":bug: Bug fixes of design" />
 | 
			
		||||
    <MESSAGE value=":sparkles: Bug fixes" />
 | 
			
		||||
    <option name="LAST_COMMIT_MESSAGE" value=":sparkles: Bug fixes" />
 | 
			
		||||
    <MESSAGE value=":sparkles: Batch mark notify as read API" />
 | 
			
		||||
    <option name="LAST_COMMIT_MESSAGE" value=":sparkles: Batch mark notify as read API" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="VgoProject">
 | 
			
		||||
    <settings-migrated>true</settings-migrated>
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ func getToken(c *fiber.Ctx) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid password: %v", err.Error()))
 | 
			
		||||
		} else if err := ticket.IsAvailable(); err != nil {
 | 
			
		||||
			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("risk detected: %v", err))
 | 
			
		||||
			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("risk detected: %v (ticketId=%d)", err, ticket.ID))
 | 
			
		||||
		}
 | 
			
		||||
		access, refresh, err = services.ExchangeOauthToken(data.ClientID, data.ClientSecret, data.RedirectUri, *ticket.GrantToken)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,21 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func DetectRisk(user models.Account, ip, ua string) bool {
 | 
			
		||||
	var availableFactor int64
 | 
			
		||||
	if err := database.C.
 | 
			
		||||
		Where(models.AuthFactor{AccountID: user.ID}).
 | 
			
		||||
		Where("type != ?", models.PasswordAuthFactor).
 | 
			
		||||
		Model(models.AuthFactor{}).
 | 
			
		||||
		Where(&availableFactor); err != nil || availableFactor <= 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var secureFactor int64
 | 
			
		||||
	if err := database.C.Where(models.AuthTicket{
 | 
			
		||||
		AccountID: user.ID,
 | 
			
		||||
		IpAddress: ip,
 | 
			
		||||
	}).Model(models.AuthTicket{}).Count(&secureFactor).Error; err == nil {
 | 
			
		||||
	if err := database.C.
 | 
			
		||||
		Where(models.AuthTicket{AccountID: user.ID, IpAddress: ip}).
 | 
			
		||||
		Where("available_at IS NOT NULL").
 | 
			
		||||
		Model(models.AuthTicket{}).
 | 
			
		||||
		Count(&secureFactor).Error; err == nil {
 | 
			
		||||
		if secureFactor >= 1 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -83,6 +83,7 @@
 | 
			
		||||
        html, body {
 | 
			
		||||
            padding: 0;
 | 
			
		||||
            margin: 0;
 | 
			
		||||
            background-color: var(--md-sys-color-surface-container);
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,13 @@
 | 
			
		||||
<div class="right-part">
 | 
			
		||||
    <div class="responsive-title-gap"></div>
 | 
			
		||||
 | 
			
		||||
    <div class="action-form">
 | 
			
		||||
        <div class="input-label">Avatar</div>
 | 
			
		||||
    <div class="personalize-actions">
 | 
			
		||||
        <md-filled-tonal-button class="personalize-action" data-target="avatar">
 | 
			
		||||
            Edit Avatar
 | 
			
		||||
            <span slot="icon" class="material-symbols-outlined">account_circle</span>
 | 
			
		||||
        </md-filled-tonal-button>
 | 
			
		||||
        <input
 | 
			
		||||
                hidden
 | 
			
		||||
                id="avatar-input"
 | 
			
		||||
                class="block-field"
 | 
			
		||||
                name="avatar"
 | 
			
		||||
@@ -19,8 +23,12 @@
 | 
			
		||||
                placeholder="Avatar"
 | 
			
		||||
        >
 | 
			
		||||
 | 
			
		||||
        <div class="input-label">Banner</div>
 | 
			
		||||
        <md-filled-tonal-button class="personalize-action" data-target="banner">
 | 
			
		||||
           Edit Banner
 | 
			
		||||
            <span slot="icon" class="material-symbols-outlined">background_replace</span>
 | 
			
		||||
        </md-filled-tonal-button>
 | 
			
		||||
        <input
 | 
			
		||||
                hidden
 | 
			
		||||
                id="banner-input"
 | 
			
		||||
                class="block-field"
 | 
			
		||||
                name="banner"
 | 
			
		||||
@@ -30,8 +38,6 @@
 | 
			
		||||
        >
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <md-divider style="margin: 1rem 0"></md-divider>
 | 
			
		||||
 | 
			
		||||
    <form class="action-form" action="/users/me/personalize" method="POST">
 | 
			
		||||
        <div class="columns-two">
 | 
			
		||||
            <md-outlined-text-field
 | 
			
		||||
@@ -110,9 +116,32 @@
 | 
			
		||||
        font-size: 14px;
 | 
			
		||||
        text-align: left;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .personalize-actions {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        gap: 0.5rem;
 | 
			
		||||
        margin-bottom: 1.5rem;
 | 
			
		||||
        margin-left: -0.2rem;
 | 
			
		||||
        margin-right: -0.2rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .personalize-actions .personalize-action {
 | 
			
		||||
        width: fit-content;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .personalize-action .material-symbols-outlined {
 | 
			
		||||
        font-size: 20px;
 | 
			
		||||
        margin-bottom: 2px;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    document.querySelectorAll(".personalize-action").forEach((element) => {
 | 
			
		||||
        element.addEventListener("click", (_) => {
 | 
			
		||||
            document.getElementById(`${element.getAttribute("data-target")}-input`).click();
 | 
			
		||||
        })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    document.getElementById("avatar-input").addEventListener("input", (evt) => {
 | 
			
		||||
        if (!evt.target.files) return
 | 
			
		||||
        const data = new FormData();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user