Skip to content

Commit 36ed504

Browse files
committed
Add 'docs/' from commit 'e79c39c42cac3342e38638aced289b3a5b74ae44'
git-subtree-dir: docs git-subtree-mainline: 65ca557 git-subtree-split: e79c39c
2 parents 65ca557 + e79c39c commit 36ed504

File tree

13 files changed

+2161
-0
lines changed

13 files changed

+2161
-0
lines changed

docs/admin-panel.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
title: Admin panel
3+
---
4+
5+
The Cot admin panel provides an automatic interface for managing your models. It allows you to add, edit, delete and view records without writing any custom views or templates. This is perfect for prototyping your application and for managing your data in cases where you don't need a custom interface, as the Cot admin panel is automatically generated based on your models.
6+
7+
## Enabling the Admin Interface
8+
9+
First, add the admin app and the dependencies required to your project in `src/main.rs`:
10+
11+
```rust
12+
use cot::admin::AdminApp;
13+
use cot::auth::db::{DatabaseUser, DatabaseUserApp};
14+
use cot::middleware::SessionMiddleware;
15+
use cot::project::{MiddlewareContext, RegisterAppsContext, RootHandler, RootHandlerBuilder};
16+
use cot::static_files::StaticFilesMiddleware;
17+
18+
struct MyProject;
19+
20+
impl Project for MyProject {
21+
fn register_apps(&self, apps: &mut AppBuilder, _context: &RegisterAppsContext) {
22+
apps.register(DatabaseUserApp::new()); // Needed for admin authentication
23+
apps.register_with_views(AdminApp::new(), "/admin"); // Register the admin app
24+
apps.register_with_views(MyApp, "");
25+
}
26+
27+
fn middlewares(
28+
&self,
29+
handler: RootHandlerBuilder,
30+
app_context: &MiddlewareContext,
31+
) -> RootHandler {
32+
handler
33+
.middleware(StaticFilesMiddleware::from_context(app_context))
34+
.middleware(SessionMiddleware::new()) // Required for admin login
35+
.build()
36+
}
37+
38+
// ...
39+
}
40+
```
41+
42+
## Admin User Creation
43+
44+
By default, the admin interface uses Cot's authentication system. Therefore, you need to create an admin user if it doesn't exist:
45+
46+
```rust
47+
use async_trait::async_trait; // cargo add async-trait
48+
use cot::ProjectContext;
49+
use cot::auth::db::DatabaseUser;
50+
use cot::common_types::Password;
51+
use std::env;
52+
53+
// In your main.rs:
54+
#[async_trait]
55+
impl App for MyApp {
56+
async fn init(&self, context: &mut ProjectContext) -> cot::Result<()> {
57+
// Check if admin user exists
58+
let admin_username = env::var("ADMIN_USER")
59+
.unwrap_or_else(|_| "admin".to_string());
60+
let user = DatabaseUser::get_by_username(context.database(), &admin_username).await?;
61+
if user.is_none() {
62+
let password = env::var("ADMIN_PASSWORD")
63+
.unwrap_or_else(|_| "change_me".to_string());
64+
// Create admin user
65+
DatabaseUser::create_user(
66+
context.database(),
67+
&admin_username,
68+
&Password::new(&password)
69+
).await?;
70+
}
71+
Ok(())
72+
}
73+
}
74+
```
75+
76+
## Registering Models in the Admin
77+
78+
To make your models appear in the admin interface, you need to implement the `AdminModel` trait. The easiest way is to use the `#[derive(AdminModel)]` macro:
79+
80+
```rust
81+
use cot::admin::AdminModel;
82+
use cot::db::{model, Auto};
83+
use cot::form::Form;
84+
85+
#[derive(Debug, Form, AdminModel)]
86+
#[model]
87+
struct BlogPost {
88+
#[model(primary_key)]
89+
id: Auto<i32>,
90+
title: String,
91+
content: String,
92+
published: bool,
93+
}
94+
```
95+
96+
Note however that in order to derive the `AdminModel` trait, you need to also derive the `Form` and `Model` traits (the latter is provided by the `#[model]` attribute). In addition to that, your model needs to implement the `Display` trait—for instance, in the case above, we could add it like so:
97+
98+
```rust
99+
impl Display for BlogPost {
100+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101+
write!(f, "{}", self.title)
102+
}
103+
}
104+
```
105+
106+
After adding the `AdminModel` trait, you can add your model to the admin panel using `DefaultAdminModelManager`. This is as easy as adding the following code to your `App` implementation:
107+
108+
```rust
109+
impl App for MyApp {
110+
fn admin_model_managers(&self) -> Vec<Box<dyn AdminModelManager>> {
111+
vec![Box::new(DefaultAdminModelManager::<BlogPost>::new())]
112+
}
113+
114+
// ...
115+
}
116+
```
117+
118+
Now your model can be managed through the admin interface at `http://localhost:8000/admin/`!
119+
120+
## Summary
121+
122+
In this chapter, you learned how to enable the Cot admin panel, create an admin user, and register your models in the admin interface. In the next chapter, we'll learn how to handle static assets in Cot.

docs/caching.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: Caching
3+
---
4+
5+
Cot provides a flexible caching system that allows you to store and retrieve data quickly, reducing the load on your database and improving response times. The caching system is designed to be pluggable, meaning you can switch between different cache backends without changing your application code.
6+
7+
## Configuration
8+
9+
To use the caching system, you first need to configure it in your `ProjectConfig` (or via configuration files).
10+
11+
### Configuration via TOML
12+
13+
You can configure the cache in your `config/*.toml` files:
14+
15+
```toml
16+
[cache]
17+
prefix = "myapp" # Optional: prefix for all cache keys
18+
max_retries = 3 # Optional: max retries for cache operations (default: 3)
19+
timeout = "5s" # Optional: timeout for cache operations (default: 5s)
20+
21+
[cache.store]
22+
type = "memory" # Options: "memory", "redis", "file" (if enabled)
23+
```
24+
25+
For Redis:
26+
27+
```toml
28+
[cache.store]
29+
type = "redis"
30+
url = "redis://127.0.0.1:6379"
31+
pool_size = 20 # Optional: connection pool size
32+
```
33+
34+
## Usage
35+
36+
You can access the cache by using the `Cache` extractor. The cache interface provides standard methods like `get`, `insert`, `remove`, etc.
37+
38+
```rust
39+
use cot::cache::Cache;
40+
use cot::html::Html;
41+
42+
async fn cache_example(cache: Cache) -> cot::Result<Html> {
43+
// Insert a value (uses default expiration if set in config, or infinite)
44+
cache.insert("user_1_name", "Alice").await?;
45+
46+
// Get a value
47+
let name: Option<String> = cache.get("user_1_name").await?;
48+
49+
if let Some(n) = name {
50+
println!("Found user: {}", n);
51+
}
52+
53+
Ok(Html::new("OK"))
54+
}
55+
```
56+
57+
### Expiration
58+
59+
You can set an expiration time for specific keys:
60+
61+
```rust
62+
use std::time::Duration;
63+
use cot::config::Timeout;
64+
65+
// Cache for 60 seconds
66+
cache.insert_expiring(
67+
"temp_key",
68+
"temp_value",
69+
Timeout::After(Duration::from_secs(60))
70+
).await?;
71+
```
72+
73+
## Advanced Topics
74+
75+
#### Lazy Computation
76+
77+
You can use `get_or_insert_with` to lazily compute and cache values:
78+
79+
```rust
80+
let value: String = cache.get_or_insert_with("expensive_key", || async {
81+
// Perform expensive computation
82+
Ok("expensive_result".to_string())
83+
}).await?;
84+
```
85+
86+
#### Prefix
87+
88+
Sharing a cache instance between different environments (e.g., production and dev), or between different versions of the same
89+
application can cause data collisions and bugs. To prevent this, you can specify a prefix for the cache keys. When a prefix
90+
is set, all keys will be formatted as `{prefix}:{key}`, ensuring each server instance has its own isolated namespace.
91+
92+
The prefix can be set in the configuration file:
93+
94+
```toml
95+
[cache]
96+
prefix = "v1"
97+
```
98+
99+
## Cache Backends
100+
101+
Cot supports the following cache backends:
102+
103+
- **Memory**: Stores data in memory. Fast, but data is lost when the server restarts. Good for development or short-lived cache.
104+
- **Redis**: Stores data in a Redis instance. Persistent and shared across multiple server instances. Requires the `redis` feature.
105+
- **File**: Stores data in files. Persistent but slower than memory/Redis. Requires configuring a path.
106+
107+
To use Redis, make sure to enable the `redis` feature in your `Cargo.toml`:
108+
109+
```toml
110+
[dependencies]
111+
cot = { version = "0.5", features = ["redis"] }
112+
```

0 commit comments

Comments
 (0)