---
config:
    layout: elk
---
classDiagram
    %% Models
    class OAuthUser {
        +ForeignKey author
        +CharField openid
        +CharField nickname
        +CharField token
        +CharField picture
        +CharField type
        +CharField email
        +TextField metadata
        +DateTimeField creation_time
        +DateTimeField last_modify_time
        +__str__()
    }

    class OAuthConfig {
        +CharField type
        +CharField appkey
        +CharField appsecret
        +CharField callback_url
        +BooleanField is_enable
        +DateTimeField creation_time
        +DateTimeField last_modify_time
        +clean()
        +__str__()
    }

    %% Admin Classes
    class OAuthUserAdmin {
        +search_fields
        +list_per_page
        +list_display
        +list_display_links
        +list_filter
        +readonly_fields
        +get_readonly_fields()
        +has_add_permission()
        +link_to_usermodel()
        +show_user_image()
    }

    class OAuthConfigAdmin {
        +list_display
        +list_filter
    }

    %% Forms
    class RequireEmailForm {
        +EmailField email
        +IntegerField oauthid
        +__init__()
    }

    %% Views
    class RequireEmailView {
        +form_class
        +template_name
        +get()
        +get_initial()
        +get_context_data()
        +form_valid()
    }

    %% OAuth Manager Classes
    class BaseOauthManager {
        <<Abstract>>
        +AUTH_URL
        +TOKEN_URL
        +API_URL
        +ICON_NAME
        +access_token
        +openid
        +is_access_token_set
        +is_authorized
        +get_authorization_url()
        +get_access_token_by_code()
        +get_oauth_userinfo()
        +get_picture()
        +do_get()
        +do_post()
        +get_config()
    }

    class ProxyManagerMixin {
        +proxies
        +do_get()
        +do_post()
    }

    class WBOauthManager {
        +client_id
        +client_secret
        +callback_url
        +get_authorization_url()
        +get_access_token_by_code()
        +get_oauth_userinfo()
        +get_picture()
    }

    class GoogleOauthManager {
        +client_id
        +client_secret
        +callback_url
        +get_authorization_url()
        +get_access_token_by_code()
        +get_oauth_userinfo()
        +get_picture()
    }

    class GitHubOauthManager {
        +client_id
        +client_secret
        +callback_url
        +get_authorization_url()
        +get_access_token_by_code()
        +get_oauth_userinfo()
        +get_picture()
    }

    class FaceBookOauthManager {
        +client_id
        +client_secret
        +callback_url
        +get_authorization_url()
        +get_access_token_by_code()
        +get_oauth_userinfo()
        +get_picture()
    }

    class QQOauthManager {
        +client_id
        +client_secret
        +callback_url
        +get_authorization_url()
        +get_access_token_by_code()
        +get_open_id()
        +get_oauth_userinfo()
        +get_picture()
    }

    %% Test Classes
    class OAuthConfigTest {
        +setUp()
        +test_oauth_login_test()
    }

    class OauthLoginTest {
        +setUp()
        +init_apps()
        +get_app_by_type()
        +test_weibo_login()
        +test_google_login()
        +test_github_login()
        +test_facebook_login()
        +test_qq_login()
        +test_weibo_authoriz_login_with_email()
        +test_weibo_authoriz_login_without_email()
    }

    %% Exception Class
    class OAuthAccessTokenException {
        <<Exception>>
    }

    %% Relationships
    OAuthUserAdmin --> OAuthUser : 管理
    OAuthConfigAdmin --> OAuthConfig : 管理
    
    RequireEmailView --> RequireEmailForm : 使用
    
    BaseOauthManager <|-- WBOauthManager : 继承
    BaseOauthManager <|-- QQOauthManager : 继承
    
    BaseOauthManager <|-- GoogleOauthManager : 继承
    ProxyManagerMixin <|.. GoogleOauthManager : 混入
    
    BaseOauthManager <|-- GitHubOauthManager : 继承
    ProxyManagerMixin <|.. GitHubOauthManager : 混入
    
    BaseOauthManager <|-- FaceBookOauthManager : 继承
    ProxyManagerMixin <|.. FaceBookOauthManager : 混入
    
    BaseOauthManager --> OAuthUser : 创建
    BaseOauthManager --> OAuthConfig : 配置依赖
    
    OAuthConfigTest --> OAuthConfig : 测试
    OauthLoginTest --> BaseOauthManager : 测试
    OauthLoginTest --> OAuthConfig : 测试
    OauthLoginTest --> OAuthUser : 测试