Skip to content

Instantly share code, notes, and snippets.

@iklobato
Last active October 9, 2024 15:59
Show Gist options
  • Save iklobato/3c8875f55f183f37da5921ba7745132d to your computer and use it in GitHub Desktop.
Save iklobato/3c8875f55f183f37da5921ba7745132d to your computer and use it in GitHub Desktop.
For a given json file adds the groups and list of vvalues automatically
"""
Tag Manager for Tactiq
This script manages tags and their associated values for the Tactiq application.
It provides functionality to create tags and add values to them using the Tactiq API.
Usage:
python tag_manager.py --token=<your_token> --tags_file=<path_to_tags_file>
--token: Your Tactiq API bearer token (required)
--tags_file: Path to the JSON file containing tag groups (default: groups.json)
The tags file should be a JSON file with the following structure:
{
"tag_name_1": ["value1", "value2", ...],
"tag_name_2": ["value3", "value4", ...],
...
}
Example:
python tag_manager.py --token=abc123... --tags_file=my_tags.json
"""
import argparse
import json
import re
import requests
from dataclasses import dataclass
from typing import Dict, List, Optional
@dataclass
class Config:
"""
Configuration class for the Tag Manager.
Attributes:
token (str): The bearer token for API authentication.
tags_file (str): The path to the JSON file containing tag groups.
api_url (str): The URL of the Tactiq API (default: "https://api2.tactiq.io/api/2/graphql").
"""
token: str
tags_file: str
api_url: str = "https://api2.tactiq.io/api/2/graphql"
@property
def headers(self) -> Dict[str, str]:
"""
Generate the headers for API requests.
Returns:
Dict[str, str]: A dictionary of HTTP headers for API requests.
"""
return {
'accept': '*/*',
'accept-language': 'en;q=0.8',
'authorization': f'Bearer {self.token}',
'content-type': 'application/json',
'origin': 'https://app.tactiq.io',
'referer': 'https://app.tactiq.io/',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
}
@dataclass
class APIClient:
"""
API client for making requests to the Tactiq API.
Attributes:
config (Config): The configuration object containing API settings.
"""
config: Config
def post_request(self, payload: Dict) -> Optional[Dict]:
"""
Send a POST request to the Tactiq API.
Args:
payload (Dict): The request payload.
Returns:
Optional[Dict]: The JSON response from the API, or None if the request failed.
"""
try:
response = requests.post(
self.config.api_url, headers=self.config.headers, json=payload
)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"API request failed: {e}")
return None
class TagManager:
"""
Manages tag operations for the Tactiq application.
Attributes:
api_client (APIClient): The API client for making requests to the Tactiq API.
"""
def __init__(self, api_client: APIClient):
"""
Initialize the TagManager.
Args:
api_client (APIClient): The API client for making requests to the Tactiq API.
"""
self.api_client = api_client
@staticmethod
def sanitize_field_name(name: str) -> str:
"""
Sanitize a field name to make it suitable for use in GraphQL queries.
Args:
name (str): The original field name.
Returns:
str: The sanitized field name.
"""
sanitized = re.sub(r'\W+', '_', name)
return f'tag_{sanitized}' if not sanitized[0].isalpha() else sanitized
def create_tags(self, tags_dict: Dict[str, List[str]]) -> Optional[Dict]:
"""
Create tags using the Tactiq API.
Args:
tags_dict (Dict[str, List[str]]): A dictionary of tag names and their associated values.
Returns:
Optional[Dict]: The API response containing created tags, or None if the request failed.
"""
create_tag_mutations = [
f"""{self.sanitize_field_name(tag_name)}: createTag(input: {{name: "{tag_name}", icon: "{tag_name[0]}"}}) {{
tag {{
icon
name
__typename
}}
__typename
}}"""
for tag_name in tags_dict.keys()
]
mutation_string = "\n".join(create_tag_mutations)
payload = {
"operationName": "CreateTags",
"variables": {},
"query": f"mutation CreateTags {{{mutation_string}}}",
}
return self.api_client.post_request(payload)
def add_values_to_tags(self, tags_dict: Dict[str, List[str]]) -> Optional[Dict]:
"""
Add values to tags using the Tactiq API.
Args:
tags_dict (Dict[str, List[str]]): A dictionary of tag names and their associated values.
Returns:
Optional[Dict]: The API response confirming the addition of values, or None if the request failed.
"""
auto_highlights = [
{"searchValue": value, "autoTag": tag_name}
for tag_name, values in tags_dict.items()
for value in values
]
payload = {
"operationName": "UpdateUserSetting",
"variables": {"input": {"autoHighlights": auto_highlights}},
"query": """
mutation UpdateUserSetting($input: UpdateUserSettingInput!) {
updateUserSetting(input: $input) {
success
__typename
}
}
""",
}
return self.api_client.post_request(payload)
def process_tags(self, tags_dict: Dict[str, List[str]]) -> bool:
"""
Process tags by creating them and adding associated values.
Args:
tags_dict (Dict[str, List[str]]): A dictionary of tag names and their associated values.
Returns:
bool: True if both creating tags and adding values were successful, False otherwise.
"""
create_response = self.create_tags(tags_dict)
if not create_response:
print("Failed to create tags.")
return False
print("Created tags:")
print(json.dumps(create_response, indent=2))
print("---")
update_response = self.add_values_to_tags(tags_dict)
if not update_response:
print("Failed to add values to tags.")
return False
print("Added values to tags:")
print(json.dumps(update_response, indent=2))
return True
def parse_arguments() -> argparse.Namespace:
"""
Parse command-line arguments.
Returns:
argparse.Namespace: An object containing the parsed arguments.
"""
parser = argparse.ArgumentParser(description="Tag Manager for Tactiq")
parser.add_argument(
"--token", required=True, help="Bearer token for authentication"
)
parser.add_argument(
"--tags_file", default="groups.json", help="JSON file containing tag groups"
)
return parser.parse_args()
def load_tags_dict(file_path: str) -> Optional[Dict[str, List[str]]]:
"""
Load the tags dictionary from a JSON file.
Args:
file_path (str): The path to the JSON file containing tag groups.
Returns:
Optional[Dict[str, List[str]]]: The loaded tags dictionary, or None if loading failed.
"""
try:
with open(file_path) as json_file:
return json.load(json_file)
except FileNotFoundError:
print(f"Error: The file {file_path} was not found.")
except json.JSONDecodeError:
print(f"Error: The file {file_path} is not a valid JSON file.")
return None
def main() -> None:
"""
The main function that orchestrates the tag management process.
"""
args = parse_arguments()
config = Config(token=args.token, tags_file=args.tags_file)
tags_dict = load_tags_dict(config.tags_file)
if not tags_dict:
return
api_client = APIClient(config)
tag_manager = TagManager(api_client)
if tag_manager.process_tags(tags_dict):
print("Tag processing completed successfully.")
else:
print("Tag processing failed.")
if __name__ == '__main__':
"""
This script manages tags for the Tactiq application.
To use this script:
1. Ensure you have the required dependencies installed:
pip install requests
2. Prepare a JSON file (e.g., 'groups.json') with your tag groups. The file should have this structure:
{
"Tag Name 1": ["value1", "value2", "value3"],
"Tag Name 2": ["value4", "value5", "value6"],
...
}
3. Obtain your Tactiq API bearer token.
4. Run the script from the command line:
python tag_manager.py --token=your_bearer_token --tags_file=path_to_your_tags_file.json
Example:
python tag_manager.py --token=abc123... --tags_file=my_tags.json
The script will:
- Create the specified tags in your Tactiq account
- Add the associated values to each tag
- Print the results of each operation
If any errors occur during the process, they will be printed to the console.
"""
main()
@iklobato
Copy link
Author

iklobato commented Oct 9, 2024

$ python taqtic_cli.py --token=$TOKEN --tags_file=groups_refactored.json

Created tags:
{
  "data": {
    "tag__backend_languages": {
      "tag": {
        "icon": "\ud83c\udf10",
        "name": "\ud83c\udf10 backend_languages",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__web_frameworks": {
      "tag": {
        "icon": "\ud83c\udfd7",
        "name": "\ud83c\udfd7\ufe0f web_frameworks",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__api_development": {
      "tag": {
        "icon": "\ud83d\udd0c",
        "name": "\ud83d\udd0c api_development",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__database_technologies": {
      "tag": {
        "icon": "\ud83d\udcbe",
        "name": "\ud83d\udcbe database_technologies",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__orm_query_languages": {
      "tag": {
        "icon": "\ud83d\udd0d",
        "name": "\ud83d\udd0d orm_query_languages",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_architecture": {
      "tag": {
        "icon": "\ud83c\udfdb",
        "name": "\ud83c\udfdb\ufe0f backend_architecture",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_performance": {
      "tag": {
        "icon": "\u26a1",
        "name": "\u26a1 backend_performance",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_security": {
      "tag": {
        "icon": "\ud83d\udd12",
        "name": "\ud83d\udd12 backend_security",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_testing": {
      "tag": {
        "icon": "\ud83e\uddea",
        "name": "\ud83e\uddea backend_testing",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_devops": {
      "tag": {
        "icon": "\ud83d\udee0",
        "name": "\ud83d\udee0\ufe0f backend_devops",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_cloud_services": {
      "tag": {
        "icon": "\u2601",
        "name": "\u2601\ufe0f backend_cloud_services",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_data_processing": {
      "tag": {
        "icon": "\ud83d\udd04",
        "name": "\ud83d\udd04 backend_data_processing",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_networking": {
      "tag": {
        "icon": "\ud83c\udf10",
        "name": "\ud83c\udf10 backend_networking",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_scalability": {
      "tag": {
        "icon": "\ud83d\udcc8",
        "name": "\ud83d\udcc8 backend_scalability",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_monitoring_logging": {
      "tag": {
        "icon": "\ud83d\udcca",
        "name": "\ud83d\udcca backend_monitoring_logging",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_code_quality": {
      "tag": {
        "icon": "\u2728",
        "name": "\u2728 backend_code_quality",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_deployment": {
      "tag": {
        "icon": "\ud83d\ude80",
        "name": "\ud83d\ude80 backend_deployment",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    },
    "tag__backend_async_programming": {
      "tag": {
        "icon": "\u2699",
        "name": "\u2699\ufe0f backend_async_programming",
        "__typename": "Tag"
      },
      "__typename": "CreateTagResponse"
    }
  }
}
---
Added values to tags:
{
  "data": {
    "updateUserSetting": {
      "success": true,
      "__typename": "MutationResponse"
    }
  }
}
Tag processing completed successfully.

@iklobato
Copy link
Author

iklobato commented Oct 9, 2024

groups_refactored.json

{
  "🌐 backend_languages": [
    "python", "java", "javascript", "typescript", "c#", "go", "rust", "ruby", "php",
    "scala", "kotlin", "node.js", "perl", "haskell", "erlang", "elixir", "clojure",
    "swift", "dart", "lua", "julia", "f#", "groovy", "crystal", "nim"
  ],
  "πŸ—οΈ web_frameworks": [
    "django", "flask", "fastapi", "express.js", "spring boot", "asp.net core",
    "ruby on rails", "laravel", "symfony", "phoenix", "gin", "echo", "fiber",
    "nest.js", "koa.js", "sanic", "tornado", "bottle", "pyramid", "fastify",
    "actix", "rocket", "axum", "ktor", "quarkus", "micronaut", "play framework"
  ],
  "πŸ”Œ api_development": [
    "restful api", "graphql", "grpc", "soap", "websocket", "webhooks", "openapi",
    "swagger", "api versioning", "api documentation", "api security", "rate limiting",
    "api gateway", "service mesh", "api monitoring", "api analytics", "api testing",
    "json:api", "hateoas", "oauth", "jwt", "api caching", "api design patterns",
    "hypermedia apis", "server-sent events", "long polling", "api composition"
  ],
  "πŸ’Ύ database_technologies": [
    "sql", "nosql", "postgresql", "mysql", "sqlite", "oracle", "microsoft sql server",
    "mongodb", "cassandra", "redis", "elasticsearch", "neo4j", "couchdb", "dynamodb",
    "influxdb", "timescaledb", "couchbase", "mariadb", "firebase realtime database",
    "apache hbase", "ravendb", "arangodb", "scylladb", "cockroachdb", "faunadb",
    "tidb", "clickhouse", "dgraph", "apache druid", "yugabytedb"
  ],
  "πŸ” orm_query_languages": [
    "sql", "orm", "sequelize", "sqlalchemy", "hibernate", "entity framework",
    "prisma", "typeorm", "mongoose", "gorm", "doctrine", "eloquent orm",
    "peewee", "jooq", "graphql queries", "linq", "hql", "cypher", "gremlin",
    "arangodb query language", "cassandra query language",
    "mongodb query language", "n1ql", "xquery", "sparql"
  ],
  "πŸ›οΈ backend_architecture": [
    "microservices", "monolithic", "serverless", "event-driven", "soa",
    "layered architecture", "hexagonal architecture", "onion architecture",
    "clean architecture", "cqrs", "event sourcing", "domain-driven design",
    "modular monolith", "microkernel architecture", "space-based architecture",
    "saga pattern", "strangler pattern", "backend for frontend",
    "sidecar pattern", "circuit breaker pattern", "bulkhead pattern"
  ],
  "⚑ backend_performance": [
    "caching", "load balancing", "database indexing", "query optimization",
    "connection pooling", "asynchronous processing", "multithreading",
    "concurrency control", "lazy loading", "eager loading", "pagination",
    "data compression", "memory management", "cpu optimization", "i/o optimization",
    "database sharding", "read replicas", "write-behind caching", "content delivery networks",
    "database denormalization", "materialized views", "query result caching"
  ],
  "πŸ”’ backend_security": [
    "authentication", "authorization", "oauth", "jwt", "https/tls", "sql injection prevention",
    "xss prevention", "csrf protection", "password hashing", "input validation",
    "rate limiting", "firewall configuration", "cors", "security headers",
    "encryption at rest", "encryption in transit", "audit logging", "secrets management",
    "two-factor authentication", "role-based access control",
    "intrusion detection systems", "web application firewalls",
    "data masking", "penetration testing", "secure coding practices"
  ],
  "πŸ§ͺ backend_testing": [
    "unit testing", "integration testing", "functional testing", "e2e testing",
    "load testing", "stress testing", "security testing", "api testing",
    "mocking", "stubbing", "tdd", "bdd", "property-based testing",
    "mutation testing", "fuzz testing", "regression testing", "smoke testing",
    "acceptance testing", "contract testing", "performance testing",
    "chaos engineering", "canary testing", "a/b testing", "static code analysis"
  ],
  "πŸ› οΈ backend_devops": [
    "ci/cd", "docker", "kubernetes", "jenkins", "gitlab ci", "travis ci",
    "circleci", "ansible", "terraform", "chef", "puppet", "prometheus",
    "grafana", "elk stack", "nagios", "zabbix", "new relic", "datadog",
    "sonarqube", "argocd", "flux", "helm", "istio", "linkerd", "consul",
    "vault", "packer", "spinnaker", "gitops", "infrastructure as code"
  ],
  "☁️ backend_cloud_services": [
    "aws", "azure", "google cloud platform", "heroku", "digitalocean",
    "linode", "vultr", "ibm cloud", "oracle cloud", "alibaba cloud",
    "serverless computing", "faas", "paas", "iaas", "baas", "containers as a service",
    "edge computing", "hybrid cloud", "multi-cloud", "cloud-native development",
    "serverless databases", "cloud storage solutions", "content delivery networks",
    "cloud load balancers", "managed kubernetes services"
  ],
  "πŸ”„ backend_data_processing": [
    "etl", "data pipeline", "stream processing", "batch processing",
    "apache kafka", "apache spark", "apache flink", "rabbitmq", "apache nifi",
    "airflow", "luigi", "celery", "data warehousing", "data lake",
    "big data processing", "real-time analytics", "data normalization",
    "apache beam", "apache storm", "apache samza", "hadoop", "dask",
    "pyspark", "pandas", "dremio", "apache druid", "clickhouse"
  ],
  "🌐 backend_networking": [
    "tcp/ip", "http/https", "websocket", "grpc", "udp", "dns", "cdn",
    "reverse proxy", "load balancer", "vpn", "nat", "firewall",
    "sdn", "network protocols", "osi model", "api gateway", "service mesh",
    "quic", "http/3", "ipv6", "bgp", "mpls", "software-defined",
    "network function virtualization", "content-based routing"
  ],
  "πŸ“ˆ backend_scalability": [
    "horizontal scaling", "vertical scaling", "auto-scaling", "sharding",
    "partitioning", "load balancing", "distributed caching", "content delivery network",
    "database replication", "message queues", "stateless design",
    "eventual consistency", "cap theorem", "distributed consensus",
    "consistent hashing", "data partitioning strategies", "read/write splitting",
    "database federation", "elastic search", "distributed file systems",
    "distributed tracing", "service discovery", "circuit breaker pattern"
  ],
  "πŸ“Š backend_monitoring_logging": [
    "application monitoring", "infrastructure monitoring", "log aggregation",
    "distributed tracing", "error tracking", "performance profiling",
    "real-time alerting", "metrics collection", "log analysis", "health checks",
    "uptime monitoring", "sla monitoring", "resource utilization tracking",
    "synthetic monitoring", "user experience monitoring", "business metrics tracking",
    "anomaly detection", "root cause analysis", "log rotation", "centralized logging",
    "time-series databases", "observability platforms", "custom dashboards"
  ],
  "✨ backend_code_quality": [
    "code review", "static code analysis", "linting", "code formatting",
    "cyclomatic complexity", "code coverage", "technical debt management",
    "refactoring", "design patterns", "solid principles", "clean code practices",
    "code documentation", "version control best practices", "code style guides",
    "code smells detection", "automated code review tools", "pair programming",
    "code complexity metrics", "dependency management", "dead code elimination",
    "code duplication detection", "security vulnerability scanning"
  ],
  "πŸš€ backend_deployment": [
    "blue-green deployment", "canary releases", "rolling updates",
    "feature flags", "a/b testing", "infrastructure as code",
    "configuration management", "environment management", "artifact repository",
    "release management", "rollback strategies", "deployment automation",
    "immutable infrastructure", "gitops", "continuous deployment",
    "dark launching", "feature toggles", "deployment pipelines",
    "deployment monitoring", "post-deployment testing", "runbooks"
  ],
  "βš™οΈ backend_async_programming": [
    "callbacks", "promises", "async/await", "event loop", "coroutines",
    "reactive programming", "pub/sub pattern", "message queues",
    "worker pools", "task queues", "asynchronous i/o", "non-blocking operations",
    "futures and completables", "reactive streams", "actor model",
    "csp", "asynchronous generators",
    "event-driven architecture", "continuation-passing style", "async iterators"
  ],
  "Decision": [
    "go with",
    "choose between",
    "adopt",
    "implement",
    "standardize on",
    "invest in",
    "migrate to",
    "scale using",
    "optimize with",
    "secure through",
    "test via",
    "deploy using",
    "monitor with",
    "integrate",
    "refactor to",
    "outsource",
    "develop in-house",
    "partner with",
    "upgrade to",
    "switch from",
    "consolidate",
    "expand",
    "streamline",
    "automate",
    "customize"
  ],
  "Action Item": [
    "research",
    "develop",
    "set up",
    "configure",
    "implement",
    "optimize",
    "test",
    "document",
    "review",
    "update",
    "migrate",
    "secure",
    "debug",
    "refactor",
    "deploy",
    "monitor",
    "analyze",
    "integrate",
    "backup",
    "train team on",
    "prototype",
    "benchmark",
    "audit",
    "troubleshoot",
    "validate",
    "containerize",
    "orchestrate",
    "modularize",
    "streamline",
    "automate"
  ],
  "Question": [
    "why not",
    "can we",
    "did you",
    "how does",
    "what if",
    "have we considered",
    "is it possible to",
    "should we",
    "how can we",
    "what's the impact of",
    "are there alternatives to",
    "who is responsible for",
    "when should we",
    "where do we",
    "which one is better",
    "do we need to",
    "how long will it take to",
    "what's the cost of",
    "how does this affect",
    "is this scalable for",
    "what's preventing us from",
    "how do we ensure",
    "what are the risks of",
    "how does this compare to",
    "what's the benefit of",
    "how will this integrate with",
    "what's our contingency for",
    "how will this perform under",
    "what metrics should we track for",
    "how does this align with"
  ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment