Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"contracts/governance",
"contracts/insurance",
"contracts/teachlink",
"contracts/documentation",
]

[workspace.package]
Expand Down
21 changes: 21 additions & 0 deletions contracts/documentation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "teachlink_documentation"
version = "0.1.0"
edition.workspace = true
repository.workspace = true
license.workspace = true

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
soroban-sdk.workspace = true

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }

[features]
testutils = ["soroban-sdk/testutils"]

[lints]
workspace = true
233 changes: 233 additions & 0 deletions contracts/documentation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
//! TeachLink Documentation Contract
//!
//! A smart contract for managing documentation, knowledge base articles,
//! FAQs, tutorials, and community-contributed content.

#![no_std]

use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String, Vec};

/// Documentation category types
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DocCategory {
Guide,
ApiReference,
Tutorial,
Faq,
KnowledgeBase,
Troubleshooting,
}

/// Content visibility levels
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Visibility {
Public,
Community,
Private,
}

/// A documentation article
#[contracttype]
#[derive(Clone)]
pub struct Article {
pub id: String,
pub title: String,
pub content: String,
pub category: DocCategory,
pub language: String,
pub version: u32,
pub author: Address,
pub visibility: Visibility,
pub tags: Vec<String>,
pub created_at: u64,
pub updated_at: u64,
pub view_count: u64,
pub helpful_count: u64,
}

/// A FAQ entry
#[contracttype]
#[derive(Clone)]
pub struct FaqEntry {
pub id: String,
pub question: String,
pub answer: String,
pub category: String,
pub language: String,
pub author: Address,
pub created_at: u64,
pub updated_at: u64,
pub helpful_count: u64,
}

/// Documentation contract storage keys
#[contracttype]
enum DocKey {
ArticleCount,
FaqCount,
Version,
}

/// Main documentation contract
#[contract]
pub struct DocumentationContract;

#[contractimpl]
impl DocumentationContract {
/// Create a new documentation article
pub fn create_article(
env: Env,
id: String,
title: String,
content: String,
category: DocCategory,
language: String,
tags: Vec<String>,
visibility: Visibility,
author: Address,
) -> Article {
let timestamp = env.ledger().timestamp();

let article = Article {
id: id.clone(),
title,
content,
category,
language,
version: 1,
author,
visibility,
tags,
created_at: timestamp,
updated_at: timestamp,
view_count: 0,
helpful_count: 0,
};

env.storage().instance().set(&id, &article);

// Increment article count
let count_key = DocKey::ArticleCount;
let current_count: u64 = env.storage().instance().get(&count_key).unwrap_or(0);
env.storage()
.instance()
.set(&count_key, &(current_count + 1));

article
}

/// Get an article by ID
pub fn get_article(env: Env, id: String) -> Article {
env.storage().instance().get(&id).unwrap()
}

/// Update an existing article
pub fn update_article(
env: Env,
id: String,
title: String,
content: String,
tags: Vec<String>,
) -> Article {
let mut article: Article = env.storage().instance().get(&id).unwrap();

article.title = title;
article.content = content;
article.tags = tags;
article.version += 1;
article.updated_at = env.ledger().timestamp();

env.storage().instance().set(&id, &article);

article
}

/// Record a view for analytics
pub fn record_view(env: Env, article_id: String) {
let mut article: Article = env.storage().instance().get(&article_id).unwrap();
article.view_count += 1;

env.storage().instance().set(&article_id, &article);
}

/// Record that a user found an article helpful
pub fn mark_helpful(env: Env, article_id: String) {
let mut article: Article = env.storage().instance().get(&article_id).unwrap();
article.helpful_count += 1;

env.storage().instance().set(&article_id, &article);
}

/// Create a new FAQ entry
pub fn create_faq(
env: Env,
id: String,
question: String,
answer: String,
category: String,
language: String,
author: Address,
) -> FaqEntry {
let timestamp = env.ledger().timestamp();

let faq = FaqEntry {
id: id.clone(),
question,
answer,
category,
language,
author,
created_at: timestamp,
updated_at: timestamp,
helpful_count: 0,
};

env.storage().instance().set(&id, &faq);

// Increment FAQ count
let count_key = DocKey::FaqCount;
let current_count: u64 = env.storage().instance().get(&count_key).unwrap_or(0);
env.storage()
.instance()
.set(&count_key, &(current_count + 1));

faq
}

/// Get FAQ by ID
pub fn get_faq(env: Env, id: String) -> FaqEntry {
env.storage().instance().get(&id).unwrap()
}

/// Search articles by keyword (simplified implementation)
pub fn search_articles(env: Env, _query: String) -> Vec<Article> {
// In a full implementation, this would search through articles
// For now, return empty vector as placeholder
Vec::new(&env)
}

/// Get total article count
pub fn get_article_count(env: Env) -> u64 {
env.storage()
.instance()
.get(&DocKey::ArticleCount)
.unwrap_or(0)
}

/// Get total FAQ count
pub fn get_faq_count(env: Env) -> u64 {
env.storage().instance().get(&DocKey::FaqCount).unwrap_or(0)
}

/// Get current documentation version
pub fn get_version(env: Env) -> u32 {
env.storage().instance().get(&DocKey::Version).unwrap_or(1)
}

/// Update documentation version
pub fn update_version(env: Env, version: u32) {
env.storage().instance().set(&DocKey::Version, &version);
}
}
Loading