Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id 09F5BD9
	for <~netlandish/links-dev@lists.code.netlandish.com>; Tue, 25 Feb 2025 13:17:08 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.128.182; helo=mail-yw1-f182.google.com; envelope-from=peter@netlandish.com; receiver=<UNKNOWN> 
Authentication-Results: mail.netlandish.com;
	dkim=pass (1024-bit key; unprotected) header.d=netlandish.com header.i=@netlandish.com header.b=BZlwLmk2
Received: from mail-yw1-f182.google.com (mail-yw1-f182.google.com [209.85.128.182])
	by mail.netlandish.com (Postfix) with ESMTP id 146761D80C1
	for <~netlandish/links-dev@lists.code.netlandish.com>; Tue, 25 Feb 2025 13:25:21 +0000 (UTC)
Received: by mail-yw1-f182.google.com with SMTP id 00721157ae682-6fcf90d09c6so16425897b3.0
        for <~netlandish/links-dev@lists.code.netlandish.com>; Tue, 25 Feb 2025 05:25:21 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=netlandish.com; s=google; t=1740489920; x=1741094720; darn=lists.code.netlandish.com;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:from:to:cc:subject:date:message-id:reply-to;
        bh=syKOGflymI2YNmdxmK6kgcPw9S6T5nWPTMihdVpl8oQ=;
        b=BZlwLmk2l5j6pD9q6JhrkpbQx94o2RFAqU/NdPXWqFo7DMvNit7r7p+DtJPe+x9JQQ
         hCr6SBV0n/dSOn4YeUKrIPlTmUnodc/+vm2823gH0/0736pL1+qLOA20H/zEywppYJh8
         pYBy3Aa7vayWakuCPK02uDSZVA2FGjzn+OS20=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1740489920; x=1741094720;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:x-gm-message-state:from:to:cc:subject:date:message-id
         :reply-to;
        bh=syKOGflymI2YNmdxmK6kgcPw9S6T5nWPTMihdVpl8oQ=;
        b=RqhcTrzVeIuAsDhv7fkusV/1MzDIBi/zucZJmPIPA0L1M41SACIPzq8cmdlVljxEKQ
         NdFvjAYZYJZKeg/ZAzfCWa9hMAYupIYpm7XxckQLia9v2JHlQQR2hdMGrSsO2k2yNe+4
         8+Xn4jNT50bIdMtTZncEmxKvvonsG5ToWFj0TJ2etQ6MBPY6FlkTGcPgtWOOjwj+O+n/
         yKIZoBGEk7JRjm/Vo+5PJF5hBVPan+b8ZAqXG7IiYNm9eAKz5fe0Zqev/vFilx+j0G4E
         XIropko0H5gKZrK4x6MJQ/tW5CyXh/K1Z4mYUmGfDyorZTkBNB9QBBAJGWQSCFkL/7EG
         mDZw==
X-Gm-Message-State: AOJu0Yw5/WR+VawhQbzyrfeV6czCUTLaLjoIpHcLrzh0wcALb6dcAE8p
	9iiXSwd6UikWEDVa1tqltZrYWOwcedsCXxDGSH0XNpQaK3qp0/LTfKlfm2Ye3i7NNEhU5OiBDJc
	Ua1I=
X-Gm-Gg: ASbGncuQM6+7hsnKk7enTZWg3IEvT6c6UOVoT0n1IP494TuuTCcjZp1dVLiKSJ5nWtL
	VjDJlQG93PwKSju4KlRbBDA91q8MtMWDOTcH57aqoFs4JS0TYEVeqhOI1STIdl3nQqH4DBLM/TZ
	85vqJH0HATeeNJROeBuOhqz2oT8I0qE9JNNaLzktJAuX1eAdv8PuFMZj+i2csZBw/zR8XpF3l+3
	jXCFjLwEvhVUuUIkBT51/u/hN6h2npkpxOo8EqWP2DSVBJ0auUDlRgzOy/uDn22jMy4QjA+YdZc
	N3+wd3GrnBlt2kGxg8Qpy4Ng4g==
X-Google-Smtp-Source: AGHT+IGQxxNN5EhTHVysPivoCP4VY9K37nmPZrXai0CWslbdmxECCYsUGB2+0XpJPh5s48wm2NUk4A==
X-Received: by 2002:a05:690c:6112:b0:6fb:904c:d9c1 with SMTP id 00721157ae682-6fbcbdfbe62mr137708717b3.12.1740489920286;
        Tue, 25 Feb 2025 05:25:20 -0800 (PST)
Received: from localhost ([2803:2d60:1107:87f:c915:f2de:c4a2:13a])
        by smtp.gmail.com with ESMTPSA id 00721157ae682-6fd117dd8e6sm4173937b3.78.2025.02.25.05.25.19
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Tue, 25 Feb 2025 05:25:20 -0800 (PST)
From: Peter Sanchez <peter@netlandish.com>
To: ~netlandish/links-dev@lists.code.netlandish.com
Cc: Peter Sanchez <peter@netlandish.com>
Subject: [PATCH links] Add audit log when bookmarks are imported via the import tool.
Date: Tue, 25 Feb 2025 07:25:00 -0600
Message-ID: <20250225132517.29129-1-peter@netlandish.com>
X-Mailer: git-send-email 2.47.2
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

---
 core/import.go      | 52 ++++++++++++++++++++++++++++++++++++++-------
 models/audit_log.go |  7 +++---
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/core/import.go b/core/import.go
index 59e2437..1671f47 100644
--- a/core/import.go
+++ b/core/import.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"database/sql"
 	"encoding/json"
+	"fmt"
 	"links"
 	"links/models"
 	"mime/multipart"
@@ -374,7 +375,7 @@ func ImportFromPinBoard(c echo.Context, src multipart.File,
 		return err
 	}
 
-	var start, end int
+	var listlen, start, end int
 	step := 100
 
 	adapter := &importAdapter{
@@ -387,9 +388,10 @@ func ImportFromPinBoard(c echo.Context, src multipart.File,
 	gctx := c.(*server.Context)
 	billEnabled := links.BillingEnabled(gctx.Server.Config)
 
-	for start < len(pinBoardList) {
-		if end+step > len(pinBoardList) {
-			end = len(pinBoardList)
+	listlen = len(pinBoardList)
+	for start < listlen {
+		if end+step > listlen {
+			end = listlen
 		} else {
 			end += step
 		}
@@ -414,6 +416,23 @@ func ImportFromPinBoard(c echo.Context, src multipart.File,
 
 		start += step
 	}
+
+	if listlen > 0 {
+		mdata := make(map[string]any)
+		mdata["org_id"] = org.ID
+		err := models.RecordAuditLog(
+			c.Request().Context(),
+			int(user.ID),
+			c.RealIP(),
+			models.LOG_BOOKMARK_IMPORTED,
+			fmt.Sprintf("Imported %d Pinboard bookmarks into organization %s.", listlen, org.Slug),
+			mdata,
+		)
+		if err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
@@ -493,7 +512,7 @@ func ImportFromHTML(c echo.Context, src multipart.File,
 		htmlList = append(htmlList, l)
 	}
 
-	var start, end int
+	var listlen, start, end int
 	step := 100
 
 	adapter := &importAdapter{
@@ -506,9 +525,10 @@ func ImportFromHTML(c echo.Context, src multipart.File,
 	gctx := c.(*server.Context)
 	billEnabled := links.BillingEnabled(gctx.Server.Config)
 
-	for start < len(htmlList) {
-		if end+step > len(htmlList) {
-			end = len(htmlList)
+	listlen = len(htmlList)
+	for start < listlen {
+		if end+step > listlen {
+			end = listlen
 		} else {
 			end += step
 		}
@@ -533,5 +553,21 @@ func ImportFromHTML(c echo.Context, src multipart.File,
 
 		start += step
 	}
+
+	if listlen > 0 {
+		mdata := make(map[string]any)
+		mdata["org_id"] = org.ID
+		err := models.RecordAuditLog(
+			c.Request().Context(),
+			int(user.ID),
+			c.RealIP(),
+			models.LOG_BOOKMARK_IMPORTED,
+			fmt.Sprintf("Imported %d bookmarks into organization %s.", listlen, org.Slug),
+			mdata,
+		)
+		if err != nil {
+			return err
+		}
+	}
 	return nil
 }
diff --git a/models/audit_log.go b/models/audit_log.go
index 5e5f268..4a9301b 100644
--- a/models/audit_log.go
+++ b/models/audit_log.go
@@ -19,9 +19,10 @@ const (
 	LOG_ORG_ADDED   = "organization_added"
 	LOG_ORG_UPDATED = "organization_updated"
 
-	LOG_BOOKMARK_ADDED   = "bookmark_added"
-	LOG_BOOKMARK_UPDATED = "bookmark_added"
-	LOG_BOOKMARK_DELETED = "bookmark_added"
+	LOG_BOOKMARK_ADDED    = "bookmark_added"
+	LOG_BOOKMARK_UPDATED  = "bookmark_added"
+	LOG_BOOKMARK_DELETED  = "bookmark_added"
+	LOG_BOOKMARK_IMPORTED = "bookmarks_imported"
 
 	LOG_NOTE_ADDED   = "note_added"
 	LOG_NOTE_UPDATED = "note_added"
-- 
2.47.2

