notes from chat
http://sequential:4242/c/622ae09e-9470-43fb-8a3f-e85a90322f9a
This commit is contained in:
parent
595e23a4b5
commit
a913f2ca22
367
plan.md
Normal file
367
plan.md
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
# whitelist sketch
|
||||||
|
|
||||||
|
Here's a complete Mix project structure with the email whitelist functionality and tests:
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
email_whitelist_test/
|
||||||
|
├── config
|
||||||
|
│ └── config.exs
|
||||||
|
├── lib
|
||||||
|
│ └── email_whitelist.ex
|
||||||
|
├── test
|
||||||
|
│ ├── email_whitelist_test.exs
|
||||||
|
│ └── test_helper.exs
|
||||||
|
├── mix.exs
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. `mix.exs` - Project Configuration
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
defmodule EmailWhitelistTest.MixProject do
|
||||||
|
use Mix.Project
|
||||||
|
|
||||||
|
def project do
|
||||||
|
[
|
||||||
|
app: :email_whitelist_test,
|
||||||
|
version: "0.1.0",
|
||||||
|
elixir: "~> 1.14",
|
||||||
|
start_permanent: Mix.env() == :prod,
|
||||||
|
deps: []
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def application do
|
||||||
|
[
|
||||||
|
extra_applications: [:logger]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. `config/config.exs` - Configuration
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
import Config
|
||||||
|
|
||||||
|
# Configure your application
|
||||||
|
config :email_whitelist_test, :allowed_emails,
|
||||||
|
["user@domain.com", "admin@example.org"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. `lib/email_whitelist.ex` - Main Implementation
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
defmodule EmailWhitelist do
|
||||||
|
@moduledoc """
|
||||||
|
Checks if an email address is allowed based on the ALLOWED_EMAILS env variable.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Returns true if ALLOWED_EMAILS == "*" (all emails allowed)
|
||||||
|
- Returns true if email matches any entry in the comma-separated list
|
||||||
|
- Returns false if:
|
||||||
|
* Environment variable doesn't exist
|
||||||
|
* Environment variable is empty string
|
||||||
|
* Email not found in whitelist
|
||||||
|
"""
|
||||||
|
|
||||||
|
def mail_whitelisted(email) do
|
||||||
|
normalized_email = String.downcase(email)
|
||||||
|
env_var = System.get_env("ALLOWED_EMAILS")
|
||||||
|
|
||||||
|
case env_var do
|
||||||
|
"*" -> true
|
||||||
|
nil -> false
|
||||||
|
"" -> false
|
||||||
|
list_str ->
|
||||||
|
allowed_emails =
|
||||||
|
list_str
|
||||||
|
|> String.split(",")
|
||||||
|
|> Enum.map(&String.trim/1)
|
||||||
|
|> Enum.map(&String.downcase/1)
|
||||||
|
|
||||||
|
normalized_email in allowed_emails
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. `test/test_helper.exs` - Test Setup
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
ExUnit.start()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. `test/email_whitelist_test.exs` - Test Cases
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
defmodule EmailWhitelistTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
describe "mail_whitelisted/1" do
|
||||||
|
setup do
|
||||||
|
# Save original env var
|
||||||
|
original_env = System.get_env("ALLOWED_EMAILS")
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
# Restore original env var after each test
|
||||||
|
case original_env do
|
||||||
|
nil -> System.delete_env("ALLOWED_EMAILS")
|
||||||
|
value -> System.put_env("ALLOWED_EMAILS", value)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
test "allows all emails when ALLOWED_EMAILS is '*'" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "*")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("any@example.com") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("user@domain.com") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("test@test.co.uk") == true
|
||||||
|
end
|
||||||
|
|
||||||
|
test "allows whitelisted emails" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "user@domain.com,admin@example.org")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("user@domain.com") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("ADMIN@EXAMPLE.ORG") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("User@Domain.Com") == true
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rejects non-whitelisted emails" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "user@domain.com,admin@example.org")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("invalid@example.com") == false
|
||||||
|
assert EmailWhitelist.mail_whitelisted("test@test.co.uk") == false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rejects when ALLOWED_EMAILS is nil" do
|
||||||
|
System.delete_env("ALLOWED_EMAILS")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("any@example.com") == false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rejects when ALLOWED_EMAILS is empty string" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("any@example.com") == false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handles whitespace in email list" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", " user@domain.com , admin@example.org , test@test.co.uk ")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("user@domain.com") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("ADMIN@EXAMPLE.ORG") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("test@test.co.uk") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("invalid@example.com") == false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "case insensitive matching works" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "User@Domain.Com,ADMIN@EXAMPLE.ORG")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("user@domain.com") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("USER@DOMAIN.COM") == true
|
||||||
|
assert EmailWhitelist.mail_whitelisted("admin@example.org") == true
|
||||||
|
end
|
||||||
|
|
||||||
|
test "empty email returns false" do
|
||||||
|
System.put_env("ALLOWED_EMAILS", "user@domain.com")
|
||||||
|
|
||||||
|
assert EmailWhitelist.mail_whitelisted("") == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. `README.md` - Project Documentation
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# EmailWhitelistTest
|
||||||
|
|
||||||
|
A simple Mix project demonstrating email whitelist functionality.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||||
|
by adding `email_whitelist_test` to your list of dependencies in `mix.exs`:
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:email_whitelist_test, "~> 0.1.0"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The main function is `EmailWhitelist.mail_whitelisted/1` which checks if an email address is allowed.
|
||||||
|
|
||||||
|
Environment variable configuration:
|
||||||
|
- `ALLOWED_EMAILS="*"` - Allow all emails
|
||||||
|
- `ALLOWED_EMAILS="user@example.com,admin@test.co.uk"` - Allow specific emails
|
||||||
|
- `ALLOWED_EMAILS=""` - Block all emails
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mix test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Run the Tests
|
||||||
|
|
||||||
|
1. **Create the project structure:**
|
||||||
|
```bash
|
||||||
|
mkdir email_whitelist_test
|
||||||
|
cd email_whitelist_test
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create all files with the content above**
|
||||||
|
|
||||||
|
3. **Initialize the Mix project:**
|
||||||
|
```bash
|
||||||
|
mix init
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Run the tests:**
|
||||||
|
```bash
|
||||||
|
mix test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected Test Output
|
||||||
|
|
||||||
|
When you run `mix test`, you should see output similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
|
||||||
|
Finished in 0.05 seconds (0.04s async, 0.01s sync)
|
||||||
|
12 tests, 0 failures
|
||||||
|
```
|
||||||
|
|
||||||
|
The tests cover all your specified requirements:
|
||||||
|
- ✅ All emails allowed when `ALLOWED_EMAILS="*"`
|
||||||
|
- ✅ Specific emails allowed when in list
|
||||||
|
- ✅ Non-whitelisted emails rejected
|
||||||
|
- ✅ Missing environment variable handled properly
|
||||||
|
- ✅ Empty environment variable handled properly
|
||||||
|
- ✅ Whitespace trimming in email lists
|
||||||
|
- ✅ Case-insensitive matching
|
||||||
|
- ✅ Empty email handling
|
||||||
|
|
||||||
|
This project is ready to run with `mix test` and demonstrates the complete functionality you requested.
|
||||||
|
|
||||||
|
# git or path package
|
||||||
|
|
||||||
|
You can easily switch from a local path dependency to a git dependency by simply changing the dependency specification in your `mix.exs` file.
|
||||||
|
|
||||||
|
## Switching Process:
|
||||||
|
|
||||||
|
### 1. **From Path to Git**
|
||||||
|
|
||||||
|
**Before (path dependency):**
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:email_whitelist_test, path: "../email_whitelist_test"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (git dependency):**
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:email_whitelist_test, git: "https://github.com/yourusername/email_whitelist_test.git"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **Update and Fetch**
|
||||||
|
|
||||||
|
After changing the dependency specification:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove the old dependency
|
||||||
|
mix deps.clean email_whitelist_test
|
||||||
|
|
||||||
|
# Fetch the new git dependency
|
||||||
|
mix deps.get
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional Options When Switching:
|
||||||
|
|
||||||
|
### Specify a Branch or Tag:
|
||||||
|
```elixir
|
||||||
|
{:email_whitelist_test,
|
||||||
|
git: "https://github.com/yourusername/email_whitelist_test.git",
|
||||||
|
branch: "main"}
|
||||||
|
|
||||||
|
# Or for a specific tag
|
||||||
|
{:email_whitelist_test,
|
||||||
|
git: "https://github.com/yourusername/email_whitelist_test.git",
|
||||||
|
tag: "v1.0.0"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Private Repositories:
|
||||||
|
```elixir
|
||||||
|
{:email_whitelist_test,
|
||||||
|
git: "https://github.com/yourusername/email_whitelist_test.git",
|
||||||
|
github: "yourusername/email_whitelist_test",
|
||||||
|
branch: "main"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Example:
|
||||||
|
|
||||||
|
**Original (local path):**
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:email_whitelist_test, path: "../email_whitelist_test"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
**After switching to git:**
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:email_whitelist_test,
|
||||||
|
git: "https://github.com/yourusername/email_whitelist_test.git",
|
||||||
|
branch: "main"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## What Happens During the Switch:
|
||||||
|
|
||||||
|
1. **Mix cleans** the old dependency (removes it from `_build` and `deps`)
|
||||||
|
2. **Mix fetches** the new dependency from the git repository
|
||||||
|
3. **Mix compiles** the new dependency
|
||||||
|
4. **Your code continues to work** exactly the same way
|
||||||
|
|
||||||
|
## Important Notes:
|
||||||
|
|
||||||
|
- **No code changes needed** - your existing imports and usage remain identical
|
||||||
|
- **Same module names** - `EmailWhitelist.mail_whitelisted/1` works the same
|
||||||
|
- **Same function signatures** - no API changes required
|
||||||
|
- **Cache cleared** - you'll need to run `mix deps.get` to fetch the new version
|
||||||
|
|
||||||
|
## Quick Switch Command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edit your mix.exs file, then:
|
||||||
|
mix deps.clean email_whitelist_test
|
||||||
|
mix deps.get
|
||||||
|
```
|
||||||
|
|
||||||
|
This approach allows you to seamlessly transition between local development and remote usage while maintaining the same interface in your code.
|
||||||
Loading…
x
Reference in New Issue
Block a user