Coverage for integrations / social / api_theme.py: 97.9%

47 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-12 04:49 +0000

1""" 

2HART OS Theme API — OS-wide appearance management. 

3 

4GET /api/social/theme/presets — List all theme presets 

5GET /api/social/theme/active — Get active theme (with CSS variables) 

6POST /api/social/theme/apply — Apply a preset OS-wide 

7POST /api/social/theme/customize — Agent-driven partial customization 

8GET /api/social/theme/fonts — Available font families 

9GET /api/social/theme/css — Active theme as CSS custom properties 

10""" 

11 

12import logging 

13from flask import Blueprint, jsonify, request 

14 

15logger = logging.getLogger('hevolve.api_theme') 

16 

17theme_bp = Blueprint('theme', __name__) 

18 

19 

20def _get_service(): 

21 from integrations.agent_engine.theme_service import ThemeService 

22 return ThemeService 

23 

24 

25@theme_bp.route('/api/social/theme/presets', methods=['GET']) 

26def list_presets(): 

27 svc = _get_service() 

28 return jsonify({'presets': svc.list_presets()}) 

29 

30 

31@theme_bp.route('/api/social/theme/active', methods=['GET']) 

32def get_active(): 

33 svc = _get_service() 

34 theme = svc.get_active_theme() 

35 css = svc.get_css_variables() 

36 return jsonify({'theme': theme, 'css': css}) 

37 

38 

39@theme_bp.route('/api/social/theme/apply', methods=['POST']) 

40def apply_theme(): 

41 data = request.get_json(force=True, silent=True) or {} 

42 theme_id = data.get('theme_id', '') 

43 if not theme_id: 

44 return jsonify({'error': 'theme_id required'}), 400 

45 

46 svc = _get_service() 

47 result = svc.apply_theme(theme_id) 

48 if 'error' in result: 

49 return jsonify(result), 404 

50 return jsonify(result) 

51 

52 

53@theme_bp.route('/api/social/theme/customize', methods=['POST']) 

54def customize_theme(): 

55 """Agent-driven partial customization. 

56 

57 Body examples: 

58 {"font": {"size": 16}} 

59 {"colors": {"accent": "f44336"}} 

60 {"shell": {"panel_opacity": 0.5}} 

61 """ 

62 data = request.get_json(force=True, silent=True) or {} 

63 if not data: 

64 return jsonify({'error': 'JSON body required'}), 400 

65 

66 svc = _get_service() 

67 result = svc.update_custom(data) 

68 if 'error' in result: 

69 return jsonify(result), 500 

70 return jsonify(result) 

71 

72 

73@theme_bp.route('/api/social/theme/fonts', methods=['GET']) 

74def list_fonts(): 

75 svc = _get_service() 

76 return jsonify({'fonts': svc.get_font_options()}) 

77 

78 

79@theme_bp.route('/api/social/theme/css', methods=['GET']) 

80def get_css(): 

81 svc = _get_service() 

82 css = svc.get_css_variables() 

83 return css, 200, {'Content-Type': 'text/css'}