Skip to content

泥好

存放所有 blog。

主要 for 自我回顧好抄 (咦)
可能有的:coding、翻譯、my 娛樂用、雜七雜八不知道

分類內 GAME: 奇迹暖暖 (奇暖)、世界計畫 (PrSk)


【Cs】Named Convention (命名慣例)

文前言

基於好奇研究一下通用規則。
(起因是個人寫方法名稱都很沒有規律QQ)

主文

ref: Names of Type Members - Framework Design Guidelines | Microsoft Learn
方法名稱:先v. 後 n./adj.

ref: Capitalization Conventions - Framework Design Guidelines | Microsoft Learn
方法名稱:PascalCasing
屬性、欄位:camelCasing

ref: General Naming Conventions - Framework Design Guidelines | Microsoft Learn
方法名稱:避免簡寫,例如 GetWindow() (O)、GetWin (X)

UPDATE LOG

115. 01/16 開新篇

【Cs】Google Cloud Storage + 服務帳戶

文前言

前篇:【Cs】Google Drive 自動上傳檔案並共享

這次要改成把檔案塞去 Google Cloud Storage,一樣用服務帳戶

起因是需求要把所有檔案通通塞雲端,不要夾帶檔案。
需求:pdf-上傳、開檔案共享連結、刪除

主文

一樣先建好服務帳戶。
服務帳戶建立方法可參見前篇,有加上如何建立的段落。

接下來是...
開 Bucket、上傳、開檔案共享連結、刪除

使用刪除的原因是檔案留存在 Cloud Storage 越久,費用越高
不如在不需要用到該檔案時,用程式觸發刪除。

那麼因為雖然存放時間不一定,但一定不會超過半個月,所以這裡就選擇 Standard 了。
詳細想自行決定可參考:Cloud Storage 教學―費用節省訣竅、使用方式完整介紹 - Cloud Ace
裡面有表格告知儲存空間級別的差別。

Bucket

需要 Bucket 的原因是檔案要留在 Cloud Storage,就需要有個 Bucket 存放。

  1. 從下圖點開

  2. 按 [建立]

  3. 填寫,這裡個人幾乎都保留預設值

    右側面板可以簡單預估可能產生的費用

安裝套件

以下是個人有用到的套件:

Google.Apis.Auth
(需要:Google.ApisGoogle.Apis.Core)

Google.Cloud.Storage.V1
(需要:Google.Apis.StorageGoogle.Api.GaxGoogle.Api.Gax.Rest)

Google.Api.Gax v4.9.0
Google.Api.Gax.Rest v4.9.0
Google.Apis v1.73.0
Google.Apis.Auth v1.73.0
Google.Apis.Core v1.73.0
Google.Apis.Storage.v1 v1.69.0.3707
Google.Cloud.Storage.V1 v4.13.0

驗證身分

沒有身分給驗證是不能做事的!

回到開好的 Bucket,點選 [授予存取權]

在打開的右側面板,填上剛剛建好的服務帳戶的電子郵件

指派角色,這裡先嘗試選擇使用者

好了按 [儲存]。

程式中如何取得服務帳戶,原本想參照前篇 【Cs】Google Drive 自動上傳檔案並共享-取得權限
然而發現完全不能通用QQ 那版是走 Drive 的,不是 GCS

諮詢了 Claude 給出的解法:

string jsonPath = @"C:\path\to\your-service-account-key.json"; 
GoogleCredential credential = GoogleCredential.FromFile(jsonPath);

具體就修改為自己的資訊就好了。

*** 在我研究的期間,Google.Apis.Auth.OAuth2 從 v1.69.0 更新到 v1.73.0
因此憑證撈取寫法稍微改動了,在 .FromFile() 那出現了警告:

CS0618 'GoogleCredential.FromJson(string)' is obsolete:

'This method is being deprecated because of a potential security risk.
Use the methods in the CredentialFactory class instead.
A GoogleCredential object can then be created by calling the .ToGoogleCredential() method on the returned specific credential. '

處理來源 Pull request:
feat: Add credential type parameter to CredentialFactory by robertvoinescu-work · Pull Request #3064 · googleapis/google-api-dotnet-client

如果想改成最新版寫法,請見:
c# - Firebase version 3.4.0 not support GoogleCredential.FromFile("") - Stack Overflow

上傳

官方ref: 上傳和下載  |  Cloud Storage  |  Google Cloud Documentation

因為是第一次嘗試,所以先用單一要求上傳試試看。

接著,因為是從本機做檔案上傳,所以繼續參照
官方ref: 從檔案系統上傳物件  |  Cloud Storage  |  Google Cloud Documentation

所需權限的部分
因為上傳跟刪除是不同系統,所以分開需求
1. storage.objects.createstorage.objects.delete 2. storage.objects.delete
(依照官方文件,delete 是在覆蓋檔案用的。)

Warning

GCS 跟 Google Drive 不同的是同名檔案在 GCS 內會被覆蓋
若不想覆蓋,要另外啟用功能 物件版本管理

純上傳的部分,官方文件就有給出:
從檔案系統上傳物件  |  Cloud Storage  |  Google Cloud Documentation
個人是用 C#,照抄稍微調一下就好。
*** 記得指定 content type 參數!以 pdf 為例,指定好可以利用連結直接預覽檔案。

上傳成功的話,會出現

再次上傳一次,因為個人沒有特別需求,所以同樣檔名上傳會蓋掉原檔案。

列表

官方文件:List Objects  |  Cloud Storage  |  Google Cloud Documentation

很基本的使用了:
## 列出值區中的物件 | List Objects  |  Cloud Storage  |  Google Cloud Documentation
官方文件給出的 C# 一丟就能用了,因此不在此做過多描述。

篩選

官方提供了兩個可供篩選的選項:前綴、delimiter(定界符)

前綴:給定前綴字串,可以篩選列出所有前綴為它的物件們
delimiter(定界符): 可限制是否只在給定的目錄底下搜尋

這裡因為個人只需要用到前綴,所以只研究前綴撰寫。
撰寫方式跟列表差不多,只差在加上一個前綴參數就好。

原本:

var storageObjects = storage.ListObjects(bucketName);
加上前綴:
var storageObjects = storage.ListObjects(bucketName, **prefix**);

預覽

需求是跟前篇一樣,使用連結可以打開 pdf 預覽。

先看一眼檔案:

其中「已通過驗證的網址」是我可能需要的預覽 pdf 連結,所以目標是抓到它。

程式面上,只找到最相近的官方文件是 下載物件  |  Cloud Storage  |  Google Cloud Documentation

因此決定直接摸索從 列表 那撈出的 Google.Apis.Storage.v1 dll (?)

.Data.Object 內觀察:

發現那兩個參數給出的結果跟前面兩個網址都不一樣@@
所以也不對。

於是問了 Claude,得到以下解法:

方案 1:使用 Signed URL(推薦)

相關官方文件:

因此:

  1. 變更服務帳戶權限,加上 token creator
  2. 確認服務帳戶對 bucket 依舊有「Storage 物件使用者」權限
  3. (應該算是誤打誤撞w)
  4. 撰寫程式碼
    // Signed URL 生成流程
    // 1. 使用服務帳戶的私鑰對 URL 進行簽署
    // 2. 生成包含簽章和過期時間的臨時 URL
    // 3. 任何人在有效期內都可透過此 URL 存取檔案
    // 4. 過期後 URL 自動失效
    
    // 需要的參數:
    // - Bucket 名稱
    // - Object 名稱(PDF 檔案路徑)
    // - 有效期限(如 1 小時、7 天等)
    // - 服務帳戶 credential(含私鑰)
    
  5. 重要提醒
    • Signed URL 特性
      • ✅ 任何人都可以透過此 URL 存取檔案(無需登入)
      • ✅ 有時間限制(最長 7 天)
      • ✅ 無法撤銷(過期前一直有效)
      • ✅ 不需要 bucket 設為公開
      • ✅ 更安全(相比永久公開)
    • 有效期限建議
      • 臨時預覽:1-2 小時
      • 分享連結:24 小時
      • 長期存取:7 天(最大值)

具體實作:

  • 其中 objectName 是檔名喔。(應該...?總之個人用檔名送有成功)
    /// <summary>
    /// 取得 Signed Url
    /// </summary>
    /// <param name="objectName"></param>
    /// <returns></returns>
    private string GenerateSignedUrl(string objectName)
    {
        // 載入憑證
        GoogleCredential credential = GetGcsCredential();
    
        // 建立 UrlSigner
        UrlSigner urlSigner = UrlSigner.FromCredential(credential);
    
        // 設定有效期限 (這裡個人設7天)
        TimeSpan duration = TimeSpan.FromDays(7);
    
        // 產生 Signed URL
        return urlSigner.Sign(bucketName, objectName, duration);
    }
    

刪除

雖說預覽有做有效期限,但個人需求並不是永久保留檔案在 GCS 上
(考量到檔案留越久費用越高問題)

因此需要做個刪除處理。

官方文件:刪除物件  |  Cloud Storage  |  Google Cloud Documentation

刪除前記得先確認好官方提示:

官方文件給出的 C# 一丟就能用了,因此不在此做過多描述。

UPDATE LOG

115. 01/09 開新文

Bugzilla

文前言

意外需要正式使用了...
原本要調一調 【雜記】自架 BugZilla 那篇擴充,但發現架構太冗+那篇是雜記,因此改成開新篇。

v5.2

主文

建立 Product

建立帳號並登入後的首先:

點選上方導覽列內的 [Administration]
然後 > [Products] > [Add] a product
會看到以下畫面:

一開始有點疑惑為甚麼 Component 是必填,因此問了 Claude:

## Bugzilla 的資料結構設計

Bugzilla 的 bug 追蹤系統採用階層式架構:

- **Product**(產品)
- **Component**(元件)← 必須存在
- **Bug**(問題單)

在這個設計中,每個 bug 必須同時關聯到一個產品和一個元件。這是 Bugzilla 資料庫架構的基本要求,bug 表格中的 component_id 欄位是必填的。

## 為什麼這樣設計

### 1. 責任歸屬的明確性

元件機制強制您在組織層面就思考清楚責任劃分。每個元件都必須指定預設負責人(Default Assignee),確保每個提交的 bug 都有明確的處理人員。

### 2. 避免過於粗糙的分類

如果只有產品層級,大型專案會面臨所有 bug 都混在一起的問題。強制使用元件可以防止這種情況,促使團隊進行更細緻的問題分類。

### 3. 通知機制的精準度

元件層級的 CC 清單和負責人設定,讓相關人員只接收到他們關心的領域的通知,避免資訊過載。

## 實務上的應對方式

如果您的專案確實很小或很簡單,不需要複雜的分類,可以採用以下策略:

### 最簡方案

建立一個通用元件,例如:

- 元件名稱:「General」或「Default」
- 描述:「一般性問題」或「未分類問題」

這樣至少滿足系統要求,之後如果專案成長需要更細的分類,再新增其他元件即可。

### 實際考量

即使是小專案,通常還是能找到基本的功能區分,例如:

- Frontend / Backend
- UI / API / Database
- Documentation / Code

這樣的基本分類對後續問題追蹤和統計分析也會有幫助。

## 結論

Bugzilla 強制要求元件不是為了增加複雜度,而是為了確保問題追蹤的品質和可維護性。這是系統設計的核心理念之一。如果您的使用場景真的非常簡單,建立一個預設的通用元件就能滿足需求,不會造成太大負擔。

因為個人還沒預備好要細分,因此先給名字「Default」。

[version] 欄位放上該系統目前已釋出的最新版本 (先簡單打個 1.0.0)
[Default Assignee] 必填,所以先填了自己。(方式是打上自己的帳號,打到一部分的時候系統會自動跳出自己的下拉選項,選擇就好)
[Default CC list] 非必填,個人還是選擇填自己

其他維持預設。

填寫結束後點選 [Add]。

Component 帶模板

為了讓別人方便依照我想要的格式,決定改 Component 成兩個:
Feature、Bug

這樣就可以各自給模板了!

回報 bug

點選右上角的 [New] 進入下圖頁面:

選擇要回報的 Product 進入下圖頁面:

先來了解一下 Severity 吧:

How severe the bug is, or whether it's an enhancement.

也就是 bug 的嚴重程度 or 純希望增強的功能。
(以下名詞解釋都有參考網路)

  • blocker:
    • 完全阻止使用或測試系統 4
  • critical:
    • 嚴重影響產品使用,系統支援問題,安全性問題 1
    • 造成產品/服務無法使用 3
  • major:
    • 重要 2
    • 主要功能無法使用 3
  • normal:
    • 普通 2
  • minor:
    • 次要 2
    • 功能無法使用/不如預期,但使用者可以自己找到解決方法,或不影響操作 3
  • trivial:
    • 外觀或風格上的問題,對功能影響極小或沒有影響。 4
  • enhancement:
    • 不急著這個開發階段修正的小問題 1
Hardware

PC: 應該可以認知為 Windows 相關產品?
Macintosh: 查網路得知是 Mac 5
Other: 安卓的手機平板應該就填這裡了

其他欄位

選擇想要回報的 [Component] 及 [Version]

[Summary]
如果有在回報 GitHub 之類的 issue 應該大概都知道要寫啥
總之就是短小精煉 & 方便被後來人搜尋到關鍵字。
以及內部公司使用記得界定好模板寫法。
輸入期間底下會多出 [Possible Duplicates],可以檢查一下有沒有類似的回報避免重複回報:

[Description]
似乎沒有支援 Markdown 語法?

[Attachment]
要附上截圖啥的好地方。
點選 [Add an attachment] 會得到下圖:

看檔案大小限制,應該只能丟截圖。
(略為翻了一下以前的影片檔,6秒就4千多kb了)

刪除 bug

ref: How To Delete Bugs in Bugzilla – devZing Blog

官方建議是不要刪除,但我加了一個測試 email 有沒有寄信到我這裡的 bug 要怎麼刪除?

  1. 上方導覽列 [Administration] > [Parameters] > [Administrative Policies]
  2. 找到參數 allowbugdeletion,改成 [On],然後 [Save Changes]
  3. 接下來將該 bug 指派給新的 Component (這裡我如同參考網站內的作法,新增一個 Trash component)
  4. 刪除該 component
  5. 把參數改回 [Off] > [Save Changes]

要注意的是該參數的描述:

The pages to edit products and components can delete all associated bugs when you delete a product (or component). Since that is a pretty scary idea, you have to turn on this option before any such deletions will ever happen.

(在編輯產品及子產品的頁面刪除一項產品或子產品時,可以刪除所有相關的 bug。)

刪除該 component 會出現提示:

所以如果可以的話,請不要刪掉 bug...

UPDATE LOG

114. 12/02 開新篇